├── .gitignore
├── 1AF1BD94-9430-4FA7-911C-2123C29C8B63.png
├── 5D87F5EF-371D-4C05-A410-30A647BD83EA.png
├── 66C1B8E8-FFF4-4200-BCFF-7B45F7B8F5B8.png
├── LICENSE
├── Packal Updater.alfredworkflow
├── Readme.md
├── alfred.bundler.php
├── alfred.bundler.sh
├── assets
├── alfred.cron.script.php
└── icons
│ ├── applications-education-miscellaneous.png
│ ├── applications-system.png
│ ├── chronometer.png
│ ├── code-context.png
│ ├── dialog-cancel.png
│ ├── dialog-close.png
│ ├── dialog-ok-apply.png
│ ├── dialog-ok.png
│ ├── document-revert.png
│ ├── download-later.png
│ ├── edit-delete.png
│ ├── flag-black.png
│ ├── flag-blue.png
│ ├── flag-green.png
│ ├── flag-red.png
│ ├── flag-yellow.png
│ ├── flag.png
│ ├── get-hot-new-stuff.png
│ ├── help-about.png
│ ├── im-ban-kick-user.png
│ ├── im-ban-user.png
│ ├── im-invisible-user.png
│ ├── im-kick-user.png
│ ├── im-user-busy.png
│ ├── im-user-offline.png
│ ├── im-user.png
│ ├── list-add-user.png
│ ├── list-add.png
│ ├── list-remove-user.png
│ ├── list-resource-add.png
│ ├── mail-mark-notjunk.png
│ ├── meeting-chair.png
│ ├── package.png
│ ├── player-time.png
│ ├── process-stop.png
│ ├── run-build-configure.png
│ ├── run-build-install-root.png
│ ├── run-build-install.png
│ ├── run-build.png
│ ├── security-high.png
│ ├── security-low.png
│ ├── security-medium.png
│ ├── svn-commit.png
│ ├── system-help.png
│ ├── system-suspend-hibernate.png
│ ├── task-accepted.png
│ ├── task-attempt.png
│ ├── task-attention.png
│ ├── task-complete.png
│ ├── task-delegate.png
│ ├── task-ongoing.png
│ ├── task-reject.png
│ ├── user-away.png
│ ├── user-busy.png
│ ├── user-invisible.png
│ ├── user-offline.png
│ ├── user-online.png
│ ├── user-properties.png
│ ├── view-media-artist.png
│ ├── view-web-browser-dom-tree.png
│ └── window-close.png
├── check-and-kill-webserver.sh
├── cli
├── includes
│ ├── plist-functions.php
│ └── plist-migration.php
├── packal.php
└── packal.sh
├── config.php
├── favicon.ico
├── functions.php
├── gui
├── assets
│ ├── css
│ │ ├── font-awesome.min.css
│ │ ├── normalize.css
│ │ └── style.css
│ ├── fonts
│ │ ├── Montserrat
│ │ │ ├── IQHow_FEYlDC4Gzy_m8fcnbFhgvWbfSbdVg11QabG8w.woff
│ │ │ ├── montserrat.css
│ │ │ └── zhcz-_WihjSQC0oHJ9TCYL3hpw3pgy2gAi-Ip7WPMi0.woff
│ │ ├── Source Sans Pro
│ │ │ ├── M2Jd71oPJhLKp0zdtTvoM_bce-VcyLJMRR1FC9qWbU8.woff
│ │ │ ├── ODelI1aHBYDBqgeIAH2zlNHq-FFgoDNV3GTKpHwuvtI.woff
│ │ │ ├── fpTVHK8qsXbIeTHTrnQH6H7XMO6S-yJpg1torQFmnv33rGVtsTkPsbDajuO5ueQw.woff
│ │ │ ├── fpTVHK8qsXbIeTHTrnQH6J4LxuTxC3JbLqy8IUt0K1T3rGVtsTkPsbDajuO5ueQw.woff
│ │ │ ├── fpTVHK8qsXbIeTHTrnQH6MJvEBP8Mx4XcuTrPnlPwTr3rGVtsTkPsbDajuO5ueQw.woff
│ │ │ ├── fpTVHK8qsXbIeTHTrnQH6OE3EfhCMemg4BxrY2mmJD_3rGVtsTkPsbDajuO5ueQw.woff
│ │ │ ├── fpTVHK8qsXbIeTHTrnQH6PgYMAt3u4NmhhzLLLPJ5qH3rGVtsTkPsbDajuO5ueQw.woff
│ │ │ ├── source.sans.pro.css
│ │ │ ├── toadOcfmlt9b38dHJxOBGC-IiwWNzQT_LXAtr-Ee9Pw.woff
│ │ │ ├── toadOcfmlt9b38dHJxOBGC7eGk4PJkA83J1AXCmgUfc.woff
│ │ │ ├── toadOcfmlt9b38dHJxOBGCmgpmuQqK2I-L2S9cF65Ek.woff
│ │ │ ├── toadOcfmlt9b38dHJxOBGIqjGYJUyOXcBwUQbRaNH6c.woff
│ │ │ └── toadOcfmlt9b38dHJxOBGMVNtom4QlEDNJaqqqzqdSs.woff
│ │ ├── fontawesome-webfont.woff
│ │ └── fonts.css
│ ├── images
│ │ ├── circle_down.svg
│ │ ├── circle_ok.svg
│ │ ├── cloud_fail.svg
│ │ ├── cloud_ok.svg
│ │ ├── cog.svg
│ │ ├── package.png
│ │ ├── packal-man.jpg
│ │ ├── paypal.gif
│ │ ├── preloader.gif
│ │ ├── refresh.svg
│ │ ├── settings.svg
│ │ ├── user-no.svg
│ │ ├── user-yes.svg
│ │ └── warning.svg
│ └── js
│ │ ├── borderMenu.js
│ │ ├── classie.js
│ │ ├── jquery-ui
│ │ └── js
│ │ │ └── jquery-ui.min.js
│ │ ├── jquery.min.js
│ │ └── keep-alive.js
├── index.php
├── packal.php
├── serve_image.php
└── webserver-keep-alive-update.php
├── icon.png
├── info.plist
├── init.php
├── install-alfred-cron-script.sh
├── libraries
└── workflows.php
├── notes.txt
├── packal-controller-script.php
├── report-usage-data.php
├── screenshots
├── gui.png
├── packal-blacklist.png
├── packal-setup.png
├── packal-start.png
├── packal-update-no-internet.png
├── packal-update.png
├── packal-updater-alfred.gif
├── packal-updater-gui.gif
└── reporting-unique-id.png
├── script-set-option.php
├── script.php
└── workflow
└── Packal Updater.alfredworkflow
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | packal
3 | packal/*
4 |
--------------------------------------------------------------------------------
/1AF1BD94-9430-4FA7-911C-2123C29C8B63.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/1AF1BD94-9430-4FA7-911C-2123C29C8B63.png
--------------------------------------------------------------------------------
/5D87F5EF-371D-4C05-A410-30A647BD83EA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/5D87F5EF-371D-4C05-A410-30A647BD83EA.png
--------------------------------------------------------------------------------
/66C1B8E8-FFF4-4200-BCFF-7B45F7B8F5B8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/66C1B8E8-FFF4-4200-BCFF-7B45F7B8F5B8.png
--------------------------------------------------------------------------------
/Packal Updater.alfredworkflow:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/Packal Updater.alfredworkflow
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | Packal Update Workflow
2 | ====
3 |
4 | By Shawn Patrick Rice
5 |
6 | This Alfred 2 workflow simply keeps your other Alfred 2/3 workflows that you've downloaded from http://www.packal.org up to date.
--------------------------------------------------------------------------------
/alfred.bundler.php:
--------------------------------------------------------------------------------
1 | /dev/null 2>&1";
27 | exec( $cmd );
28 |
29 | /**
30 | * This is the only function the workflow author needs to invoke.
31 | * If the asset to be loaded is a PHP library, then you just need to call the function,
32 | * and the files will be required automatically.
33 | *
34 | * If you are loading a "utility" application, then the function will return the full
35 | * path to the function so that you can invoke it.
36 | *
37 | * If you are passing your own json, then include it as a file path.
38 | *
39 | **/
40 | function __load( $name, $version = 'default', $type = 'php', $json = '' ) {
41 | if ( file_exists( 'info.plist' ) ) {
42 | // Grab the bundle ID from the plist file.
43 | $bundle = exec( "/usr/libexec/PlistBuddy -c 'print :bundleid' 'info.plist'" );
44 | } elseif ( file_exists( '../info.plist' ) ) {
45 | $bundle = exec( "/usr/libexec/PlistBuddy -c 'print :bundleid' '../info.plist'" );
46 | } else {
47 | $bundle = '';
48 | }
49 |
50 | if ( $type == 'php' ) {
51 | $assets = __loadAsset( $name , $version , $bundle , strtolower( $type ) , $json );
52 | foreach ( $assets as $asset ) {
53 | require_once( $asset );
54 | }
55 | return true;
56 | } elseif ( $type == 'utility' ) {
57 | $asset = __loadAsset( $name , $version , $bundle , strtolower( $type ) , $json );
58 | return str_replace( ' ' , '\ ' , $asset[0] );
59 | } else {
60 | return __loadAsset( $name , $version , $bundle , strtolower( $type ) , $json );
61 | }
62 |
63 | // We shouldn't get here.
64 | return false;
65 |
66 | } // End __load()
67 |
68 | /**
69 | * Installs the Alfred Bundler utility.
70 | **/
71 | function __installBundler() {
72 | // Install the Alfred Bundler
73 |
74 | global $bundler_version, $__data;
75 | echo 'here';
76 | $installer = "https://raw.githubusercontent.com/shawnrice/alfred-bundler/$bundler_version/meta/installer.sh";
77 | $__cache = exec( 'echo $HOME' ) . "/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/alfred.bundler-$bundler_version";
78 |
79 | // Make the directories
80 | if ( ! file_exists( $__cache ) ) {
81 | mkdir( $__cache, 0775, true );
82 | }
83 | if ( ! file_exists( "$__cache/installer" ) ) {
84 | mkdir( "$__cache/installer", 0775, true );
85 | }
86 | // Download the installer
87 | // I'm throwing in the second bash command to delay the execution of the next
88 | // exec() command. I'm not sure if that's necessary.
89 | exec( "curl -sL '$installer' > '$__cache/installer/installer.sh'" );
90 | // Run the installer
91 | exec( "sh '$__cache/installer/installer.sh'" );
92 |
93 | } // End __installBundler()
94 |
--------------------------------------------------------------------------------
/alfred.bundler.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Main Bash interface for the Alfred Dependency Bundler. This file should be
4 | # the only one from the bundler that is distributed with your workflow.
5 | #
6 | # See documentation on how to use: http://shawnrice.github.io/alfred-bundler/
7 | #
8 | # License: GPLv3
9 |
10 |
11 | # Define the global bundler version.
12 | bundler_version="aries";
13 | __data="$HOME/Library/Application Support/Alfred 2/Workflow Data/alfred.bundler-$bundler_version"
14 | __cache="$HOME/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/alfred.bundler-$bundler_version"
15 |
16 | function __load {
17 | # $1 -- asset name
18 | # $2 -- version
19 | # $3 -- type
20 | # $4 -- json -- this is a file path
21 |
22 | if [ -z "$1" ]; then
23 | echo "You need to pass at minimum one argument to use the __load function."
24 | exit 1
25 | fi
26 |
27 | local name="$1"
28 | local version="$2"
29 | local type="$3"
30 | local json="$4"
31 |
32 | if [ -z $version ]; then
33 | version="default"
34 | fi
35 | if [ -z $type ]; then
36 | type="bash"
37 | fi
38 |
39 | # Grab the bundle id.
40 | if [ -f 'info.plist' ]; then
41 | local bundle=`/usr/libexec/PlistBuddy -c 'print :bundleid' 'info.plist'`
42 | elif [ -f '../info.plist' ]; then
43 | local bundle=`/usr/libexec/PlistBuddy -c 'print :bundleid' 'info.plist'`
44 | else
45 | local bundle='..'
46 | fi
47 |
48 | __asset=`__loadAsset "$name" "$version" "$bundle" "$type" "$json"`
49 | status=$?
50 | echo "$__asset"
51 | exit "$status"
52 | }
53 |
54 | # This just downloads the install script and starts it up.
55 | function __installBundler {
56 | local installer="https://raw.githubusercontent.com/shawnrice/alfred-bundler/$bundler_version/meta/installer.sh"
57 | dir "$__cache"
58 | dir "$__cache/installer"
59 | dir "$__data"
60 | curl -sL "$installer" > "$__cache/installer/installer.sh"
61 | sh "$__cache/installer/installer.sh"
62 | }
63 |
64 | # Just a helper function to make a directory if it doesn't exist.
65 | function dir {
66 | if [ ! -d "$1" ]; then
67 | mkdir -p "$1"
68 | fi
69 | }
70 |
71 | if [ ! -f "$__data/bundler.sh" ]; then
72 | __installBundler
73 | fi
74 |
75 | # Include the bundler.
76 | . "$__data/bundler.sh"
77 |
78 | # Check for updates.
79 | sh "$__data/meta/update.sh" > /dev/null 2>&1
80 |
81 |
82 | # exit $?
--------------------------------------------------------------------------------
/assets/alfred.cron.script.php:
--------------------------------------------------------------------------------
1 | workflowReporting ) && ( $config->workflowReporting == 1 ) )
34 | exec( "php '" . $endpoints[ 'com.packal' ] . "/report-usage-data.php'" );
35 |
36 |
37 | // Grab manifest information.
38 | foreach ( $manifest as $m ) :
39 | $manifestBundles[] = $m->bundle;
40 | $wf[ "$m->bundle" ][ 'name' ] = $m->name;
41 | $wf[ "$m->bundle" ][ 'author' ] = $m->author;
42 | $wf[ "$m->bundle" ][ 'version' ] = $m->version;
43 | endforeach;
44 |
45 | $updates = false;
46 | foreach ( $endpoints as $k => $v ) :
47 | if ( file_exists( "$v/packal/package.xml" ) ) {
48 | $w = simplexml_load_file( "$v/packal/package.xml" );
49 |
50 | if ( in_array( $k, $manifestBundles ) ) {
51 | if ( $wf[ "$k" ][ 'version' ] != (string) $w->version ) {
52 | if ( ! in_array( $k, $blacklist ) ) {
53 | $updates = true;
54 | break;
55 | }
56 | }
57 | }
58 | }
59 | endforeach;
60 |
61 | if ( $updates ) {
62 | require_once( $endpoints[ 'com.packal'] . '/alfred.bundler.php' );
63 | $tn = __load( 'terminal-notifier' , 'default' , 'utility' );
64 | $cmd = 'osascript -e "tell application \"Alfred 2\" to run trigger \"com.packal.start\" in workflow \"com.packal\" with argument \"updates\""';
65 | exec( "$tn -title 'Packal Updater' -message 'You have updates for your Alfred 2 workflows available.' -group 'packal-updater' -execute '$cmd'" );
66 | }
--------------------------------------------------------------------------------
/assets/icons/applications-education-miscellaneous.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/applications-education-miscellaneous.png
--------------------------------------------------------------------------------
/assets/icons/applications-system.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/applications-system.png
--------------------------------------------------------------------------------
/assets/icons/chronometer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/chronometer.png
--------------------------------------------------------------------------------
/assets/icons/code-context.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/code-context.png
--------------------------------------------------------------------------------
/assets/icons/dialog-cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/dialog-cancel.png
--------------------------------------------------------------------------------
/assets/icons/dialog-close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/dialog-close.png
--------------------------------------------------------------------------------
/assets/icons/dialog-ok-apply.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/dialog-ok-apply.png
--------------------------------------------------------------------------------
/assets/icons/dialog-ok.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/dialog-ok.png
--------------------------------------------------------------------------------
/assets/icons/document-revert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/document-revert.png
--------------------------------------------------------------------------------
/assets/icons/download-later.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/download-later.png
--------------------------------------------------------------------------------
/assets/icons/edit-delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/edit-delete.png
--------------------------------------------------------------------------------
/assets/icons/flag-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/flag-black.png
--------------------------------------------------------------------------------
/assets/icons/flag-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/flag-blue.png
--------------------------------------------------------------------------------
/assets/icons/flag-green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/flag-green.png
--------------------------------------------------------------------------------
/assets/icons/flag-red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/flag-red.png
--------------------------------------------------------------------------------
/assets/icons/flag-yellow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/flag-yellow.png
--------------------------------------------------------------------------------
/assets/icons/flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/flag.png
--------------------------------------------------------------------------------
/assets/icons/get-hot-new-stuff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/get-hot-new-stuff.png
--------------------------------------------------------------------------------
/assets/icons/help-about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/help-about.png
--------------------------------------------------------------------------------
/assets/icons/im-ban-kick-user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/im-ban-kick-user.png
--------------------------------------------------------------------------------
/assets/icons/im-ban-user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/im-ban-user.png
--------------------------------------------------------------------------------
/assets/icons/im-invisible-user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/im-invisible-user.png
--------------------------------------------------------------------------------
/assets/icons/im-kick-user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/im-kick-user.png
--------------------------------------------------------------------------------
/assets/icons/im-user-busy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/im-user-busy.png
--------------------------------------------------------------------------------
/assets/icons/im-user-offline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/im-user-offline.png
--------------------------------------------------------------------------------
/assets/icons/im-user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/im-user.png
--------------------------------------------------------------------------------
/assets/icons/list-add-user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/list-add-user.png
--------------------------------------------------------------------------------
/assets/icons/list-add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/list-add.png
--------------------------------------------------------------------------------
/assets/icons/list-remove-user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/list-remove-user.png
--------------------------------------------------------------------------------
/assets/icons/list-resource-add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/list-resource-add.png
--------------------------------------------------------------------------------
/assets/icons/mail-mark-notjunk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/mail-mark-notjunk.png
--------------------------------------------------------------------------------
/assets/icons/meeting-chair.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/meeting-chair.png
--------------------------------------------------------------------------------
/assets/icons/package.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/package.png
--------------------------------------------------------------------------------
/assets/icons/player-time.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/player-time.png
--------------------------------------------------------------------------------
/assets/icons/process-stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/process-stop.png
--------------------------------------------------------------------------------
/assets/icons/run-build-configure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/run-build-configure.png
--------------------------------------------------------------------------------
/assets/icons/run-build-install-root.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/run-build-install-root.png
--------------------------------------------------------------------------------
/assets/icons/run-build-install.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/run-build-install.png
--------------------------------------------------------------------------------
/assets/icons/run-build.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/run-build.png
--------------------------------------------------------------------------------
/assets/icons/security-high.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/security-high.png
--------------------------------------------------------------------------------
/assets/icons/security-low.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/security-low.png
--------------------------------------------------------------------------------
/assets/icons/security-medium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/security-medium.png
--------------------------------------------------------------------------------
/assets/icons/svn-commit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/svn-commit.png
--------------------------------------------------------------------------------
/assets/icons/system-help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/system-help.png
--------------------------------------------------------------------------------
/assets/icons/system-suspend-hibernate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/system-suspend-hibernate.png
--------------------------------------------------------------------------------
/assets/icons/task-accepted.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/task-accepted.png
--------------------------------------------------------------------------------
/assets/icons/task-attempt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/task-attempt.png
--------------------------------------------------------------------------------
/assets/icons/task-attention.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/task-attention.png
--------------------------------------------------------------------------------
/assets/icons/task-complete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/task-complete.png
--------------------------------------------------------------------------------
/assets/icons/task-delegate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/task-delegate.png
--------------------------------------------------------------------------------
/assets/icons/task-ongoing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/task-ongoing.png
--------------------------------------------------------------------------------
/assets/icons/task-reject.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/task-reject.png
--------------------------------------------------------------------------------
/assets/icons/user-away.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/user-away.png
--------------------------------------------------------------------------------
/assets/icons/user-busy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/user-busy.png
--------------------------------------------------------------------------------
/assets/icons/user-invisible.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/user-invisible.png
--------------------------------------------------------------------------------
/assets/icons/user-offline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/user-offline.png
--------------------------------------------------------------------------------
/assets/icons/user-online.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/user-online.png
--------------------------------------------------------------------------------
/assets/icons/user-properties.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/user-properties.png
--------------------------------------------------------------------------------
/assets/icons/view-media-artist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/view-media-artist.png
--------------------------------------------------------------------------------
/assets/icons/view-web-browser-dom-tree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/view-web-browser-dom-tree.png
--------------------------------------------------------------------------------
/assets/icons/window-close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/assets/icons/window-close.png
--------------------------------------------------------------------------------
/check-and-kill-webserver.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Set the cache directory
4 | bundle='com.packal'
5 | file="/tmp/$bundle/zombie"
6 | # See if the time file exists; if so, check the time
7 | # Otherwise, kill the server (just in case)
8 | # And exit the script
9 |
10 | # Sleep for an initial 30 seconds to make sure that everything launches before this script goes bye-bye
11 | echo "Sleeping for thirty seconds."
12 | sleep 30
13 |
14 | alive=1
15 | echo "Waking up and starting the checks"
16 | while [ $alive -eq 1 ]
17 | do
18 | echo "Doing a check..."
19 | if [ -e "$file" ]
20 | then
21 | # Find the UNIX Epoch time
22 | now=`date +%s`
23 | # Get the last update of the webserver in Unix Epoch time (read from file)
24 | # file="/Users/Sven/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow\\ Data/com.packal/webserver/zombie"
25 | date=`cat "$file"`
26 |
27 | # Find the difference
28 | diff=`expr $now - $date`
29 | # If the difference is greater than two minutes, then kill the webserver
30 | if [ $diff -gt 120 ]
31 | then
32 | pid=`ps aux | grep 'php -S localhost:7893 -t gui' | grep -v grep | awk '{print $2}'`
33 | rm "$file"
34 | kill "$pid"
35 | echo "Killing the webserver"
36 | alive=0
37 | else
38 | echo "Webserver will live just longer"
39 | sleep 60
40 | fi
41 | else
42 | pid=`ps aux | grep 'php -S localhost:7893 -t gui' | grep -v grep | awk '{print $2}'`
43 | rm "$file"
44 | kill "$pid"
45 | echo "Killing the webserver"
46 | alive=0
47 | fi
48 | done
49 |
--------------------------------------------------------------------------------
/cli/includes/plist-functions.php:
--------------------------------------------------------------------------------
1 | toArray();
61 |
62 | if ( ! isset( $tmp['objects'] ) ) {
63 | // This is a blank Workflow. Why are you updating it?
64 | return true;
65 | }
66 |
67 | foreach ( $tmp['objects'] as $key => $object ) {
68 | if ( $object['type'] == 'alfred.workflow.trigger.hotkey' ) {
69 | // We've found a hotkey, so let's strip it.
70 | $location = ":objects:$key:config";
71 | stripHotkey( $location, $plist );
72 | }
73 | }
74 |
75 | return true;
76 | }
77 |
78 | /**
79 | * Gets the name of a workflow from its info.plist file
80 | *
81 | * @param string $dir the directory name of the workflow
82 | * @return string the name of the workflow
83 | */
84 | function getName( $dir ) {
85 | $PlistBuddy = '/usr/libexec/PlistBuddy -c ';
86 | $cmd = $PlistBuddy . "'print :name' $dir/info.plist";
87 | return exec( "$cmd" );
88 | }
89 |
90 | /**
91 | * Gets the bundle of a workflow from its info.plist file
92 | *
93 | * @param string $dir the directory name of the workflow
94 | * @return string the bundleid of the workflow
95 | */
96 | function getBundle( $dir ) {
97 | $PlistBuddy = '/usr/libexec/PlistBuddy -c ';
98 | $cmd = $PlistBuddy . "'print :bundleid' $dir/info.plist";
99 | return exec( "$cmd" );
100 | }
101 |
--------------------------------------------------------------------------------
/cli/includes/plist-migration.php:
--------------------------------------------------------------------------------
1 | toArray();
40 | /**
41 | * Load the objects array, scan through it to get everything migratable.
42 | * Store the values as an array with the UIDs as the keys.
43 | * @var array
44 | */
45 | foreach ( $tmp['objects'] as $o ) {
46 | if ( isset( $o['config'] ) ) {
47 | $original[ $o['uid'] ]['type'] = $o['type'];
48 |
49 | switch ( $o['type'] ) :
50 | case 'alfred.workflow.trigger.hotkey' :
51 | $value = array();
52 | if ( isset( $o['config']['hotkey'] ) ) {
53 | $value['hotkey'] = $o['config']['hotkey'];
54 | }
55 | if ( isset( $o['config']['hotmod'] ) ) {
56 | $value['hotmod'] = $o['config']['hotmod'];
57 | }
58 | if ( isset( $o['config']['hotstring'] ) ) {
59 | $value['hotstring'] = $o['config']['hotstring'];
60 | }
61 |
62 | $original[ $o['uid'] ]['config'] = $value;
63 | break;
64 | case 'alfred.workflow.input.filefilter' :
65 | case 'alfred.workflow.input.scriptfilter' :
66 | case 'alfred.workflow.input.keyword' :
67 | $value = array(
68 | 'keyword' => $o['config']['keyword'],
69 | );
70 | $original[ $o['uid'] ]['config'] = $value;
71 | break;
72 | endswitch;
73 |
74 | }
75 | }
76 |
77 | $tmp = $import->toArray();
78 |
79 | // The uids are stored as the keys of the $original array,
80 | // so let's grab them to check if we need to migrate anything.
81 | $uids = array_keys( $original );
82 |
83 | // These are the only types of objects that we need to migrate
84 | $objects = array(
85 | 'alfred.workflow.trigger.hotkey',
86 | 'alfred.workflow.input.filefilter',
87 | 'alfred.workflow.input.scriptfilter',
88 | 'alfred.workflow.input.keyword',
89 | );
90 |
91 | // We need the key(order) so that we can set things properly
92 | foreach ( $tmp['objects'] as $key => $o ) {
93 | // Use only the things in the types above
94 | if ( in_array( $o['type'] , $objects ) ) {
95 | // Check to see if the objects is one of the original objects with a uid.
96 | if ( in_array( $o['uid'] , $uids ) ) {
97 | echo $o['uid'] . '
';
98 | echo $o['type'] . '
';
99 | if ( $o['type'] == 'alfred.workflow.trigger.hotkey' ) {
100 | // We're not really going to bother to check to see if the values match;
101 | // we'll just migrate them instead.
102 | //setPlistValue( $location, $value, $plist)
103 | setPlistValue( ":objects:$key:config:hotmod", $original[ $o['uid'] ]['config']['hotmod'], $new );
104 | setPlistValue( ":objects:$key:config:hotkey", $original[ $o['uid'] ]['config']['hotkey'], $new );
105 | setPlistValue( ":objects:$key:config:hotstring", $original[ $o['uid'] ]['config']['hotstring'], $new );
106 | } else {
107 | // At this point, the only other thing to migrate is the keyword
108 | // Check to see if they match; if they don't, then set them to the new one
109 | if ( $o['config']['keyword'] != $original[ $o['uid'] ]['config']['keyword'] ) {
110 | setPlistValue( ":objects:$key:config:keyword", $original[ $o['uid'] ]['config']['keyword'], $new );
111 | }
112 | }
113 | }
114 | }
115 | }
116 | return true;
117 |
118 | /**
119 | *
120 | * Todo:
121 | * -- add in error checking for correct plist syntax.
122 | * -- expand migration for desired but non-essential settings
123 | *
124 | */
125 | }
126 |
127 |
--------------------------------------------------------------------------------
/cli/packal.php:
--------------------------------------------------------------------------------
1 | $opt[0];
45 | }
46 | echo $config->$opt[0];
47 |
48 | }
49 |
50 | function setOption( $opt = array() ) {
51 | global $config;
52 |
53 | $value = $opt[1];
54 | if ( $value == 'null' ) {
55 | $value = '';
56 | }
57 |
58 | $options = array(
59 | 'backups',
60 | 'auto_add',
61 | 'workflowReporting',
62 | 'notify',
63 | 'username',
64 | 'authorName',
65 | 'api_key',
66 | );
67 |
68 | $bool = array(
69 | 'auto_add',
70 | 'report',
71 | 'notify',
72 | 'packalAccount',
73 | );
74 |
75 | if ( ( ! in_array( $opt[0], $options ) ) && ( ! in_array( $opt[0], $bool ) ) ) {
76 | echo 'Error: invalid option.';
77 | return false;
78 | } elseif ( in_array( $opt[0], $bool ) && ( ! ( $value == 0 || $value == 1 ) ) ) {
79 | echo "Error: $opt[0] value must be 0 or 1.";
80 | return false;
81 | } elseif ( ( $opt[0] == 'backup' ) && ( ! is_numeric( $value ) ) ) {
82 | echo "Error: $opt[0] value must be numeric.";
83 | }
84 |
85 | // Load the config
86 | $xml = simplexml_load_file( $config );
87 |
88 | $xml->$opt[0] = $value;
89 |
90 | // Save the config again.
91 | $xml->asXml( $config );
92 | }
93 |
94 | function validateAPI( $key ) {
95 | // To be written, but not needed for this version.
96 | }
97 |
98 | ////////////////////////////////////////////////////////////////////////////////
99 | /// Check single update
100 |
101 | function checkUpdate( $wf ) {
102 | global $manifest, $cliDir;
103 |
104 | $wf = $wf[0];
105 | $dir = trim( `"$cliDir/packal.sh" getDir "$wf" 2> /dev/null` );
106 | $xml = simplexml_load_file( "$dir/packal/package.xml" );
107 | $last = $xml->updated;
108 |
109 | $xml = simplexml_load_file( "$manifest" );
110 |
111 | foreach ( $xml as $w ) :
112 | if ( $w->bundle == $wf ) {
113 | if ( "$w->updated" > "$last" ) {
114 | echo 'Needs update.';
115 | }
116 | }
117 | endforeach;
118 | }
119 |
120 | ////////////////////////////////////////////////////////////////////////////////
121 | /// Check and do all updates
122 |
123 | /**
124 | * Checks updates for all workflows (that are on Packal)
125 | */
126 | function checkUpdates( $opt = array() ) {
127 | global $manifest, $cache, $cliDir;
128 |
129 | if ( isset( $opt[0] ) ) {
130 | if ( $opt[0] == 1 ) {
131 | $yes = true;
132 | } else { $yes = false;
133 | }
134 | } else {
135 | $yes = false;
136 | }
137 | if ( isset( $opt[1] ) ) {
138 | if ( $opt[1] == 1 ) {
139 | $force = true;
140 | } else { $force = false;
141 | }
142 | } else {
143 | $force = false;
144 | }
145 |
146 | $xml = simplexml_load_file( "$manifest" );
147 | $me = getOption( array( 'username', true ) );
148 |
149 | if ( file_exists( "$cache/updates" ) ) {
150 | unlink( "$cache/updates" );
151 | }
152 |
153 | $i = 1;
154 | foreach ( $xml as $w ) :
155 | $dir = trim( `"$cliDir/packal.sh" getDir "$w->bundle" 2> /dev/null` );
156 |
157 | if ( $dir == 'FALSE' ) {
158 | continue;
159 | }
160 |
161 | if ( "$w->author" == "$me" ) {
162 | echo "* Skipping $i... $w->name ($w->bundle)\n";
163 | $i++;
164 | continue;
165 | }
166 |
167 | if ( file_exists( "$dir/packal/package.xml" ) ) {
168 | echo "Checking $i... $w->name ($w->bundle)";
169 |
170 | $wf = simplexml_load_file( "$dir/packal/package.xml" );
171 | $wf->updated += 120; // Compensation for time in the generated packages.
172 |
173 | if ( "$w->updated" > "$wf->updated" ) {
174 | echo ' — Update Available';
175 | file_put_contents( "$cache/updates", $w->bundle . "\n", FILE_APPEND );
176 | $updatable[] = array( (string) $w->name, (string) $wf->version, (string) $w->version, (string) $w->bundle );
177 | }
178 | echo "\n";
179 | $i++;
180 | } else {
181 | if ( $force == false ) {
182 | continue;
183 | }
184 |
185 | echo "Checking $i... Forcing Update for $w->name ($w->bundle)";
186 |
187 | file_put_contents( "$cache/updates", $w->bundle . "\n", FILE_APPEND );
188 | $updatable[] = array( (string) $w->name, 'Forced Update', (string) $w->version, (string) $w->bundle );
189 | echo "\n";
190 | $i++;
191 |
192 | }
193 |
194 | endforeach;
195 |
196 | if ( ( ! isset( $updatable ) ) || ( ! count( $updatable > 0 ) ) ) {
197 | echo "Everything is up to date.\n";
198 | return false;
199 | }
200 |
201 | echo 'Updates available for: ';
202 | $count = count( $updatable ) - 1;
203 | foreach ( $updatable as $u ) :
204 | echo "$u[0] ($u[1] -> $u[2])";
205 | if ( $count > 0 ) {
206 | echo ', ';
207 | } else { echo ".\n";
208 | }
209 | $count--;
210 | endforeach;
211 | echo "\n";
212 | echo "* Note: Packal tracks updates on timestamps not version numbers, so if these seem off, then the workflow author did not update the version number.\n";
213 | echo "\n";
214 | $conf = getConfirmation( $yes );
215 |
216 | if ( $conf ) {
217 | foreach ( $updatable as $u ) :
218 | echo "Trying to update $u[0] ($u[3])...";
219 | if ( doUpdate( $u[3] ) ) {
220 | echo " Success.\n";
221 | } else {
222 | echo ' ERROR.';
223 | }
224 | endforeach;
225 | } else {
226 | echo "Aborting.\n";
227 | }
228 |
229 | // While this method is incomplete, it doesn't quite matter for current functionality.
230 |
231 | }
232 |
233 | /**
234 | * Get update confirmation from the user via command line
235 | * @param bool $yes = false Automatically confirm.
236 | */
237 | function getConfirmation( $yes = false ) {
238 |
239 | if ( $yes ) {
240 | echo "Update? (Y/n): y\n";
241 | return true;
242 | }
243 |
244 | $conf = readline( 'Update? (Y/n): ' );
245 |
246 | if ( empty( $conf ) || ( $conf == 'y' ) || ( $conf == 'Y' ) ) {
247 | $response = true;
248 | } elseif ( $conf == 'n' || $conf == 'N' ) {
249 | $response = false;
250 | } else {
251 | echo "Invalid entry. Please choose y or n.\n";
252 | $response = getConfirmation();
253 | }
254 |
255 | return $response;
256 | }
257 |
258 | /**
259 | * [doUpdate description]
260 | * @param {[type]} $bundle [description]
261 | * @param {[type]} $force = false [description]
262 | */
263 | function doUpdate( $bundle, $force = false ) {
264 |
265 | global $data, $cache, $manifest, $repo, $cliDir;
266 |
267 | if ( is_array( $bundle ) ) {
268 | $bundle = $bundle[0];
269 | }
270 |
271 | $dir = trim( `"$cliDir/packal.sh" getDir "$bundle"` );
272 | // echo $dir;
273 | // The force variable means to download even if the original
274 | // is not from Packal. Obviously, since we don't have the
275 | // update data, this just means to download the update no
276 | // matter what and to get everything.
277 | if ( ! $force ) {
278 | if ( ! file_exists( "$dir/packal/package.xml" ) ) {
279 | echo 'Error: No package information exists.';
280 | return false;
281 | }
282 | }
283 |
284 | $xml = simplexml_load_file( "$manifest" );
285 |
286 | foreach ( $xml as $x ) :
287 | if ( "$x->bundle" != "$bundle" ) {
288 | continue;
289 | }
290 | $xml = $x;
291 | break;
292 | endforeach;
293 |
294 | // Make the temporary directories.
295 | if ( ! file_exists( "$cache/update" ) ) {
296 | mkdir( "$cache/update" );
297 | }
298 | if ( ! file_exists( "$cache/update/$bundle" ) ) {
299 | mkdir( "$cache/update/$bundle" );
300 | }
301 | if ( ! file_exists( "$cache/update/$bundle/tmp" ) ) {
302 | mkdir( "$cache/update/$bundle/tmp" );
303 | }
304 |
305 | `curl -sL "$repo/$bundle/$xml->file" > "$cache/update/$bundle/$xml->file"`;
306 | `curl -sL "$repo/$bundle/appcast.xml" > "$cache/update/$bundle/appcast.xml"`;
307 | `unzip -qo "$cache/update/$bundle/$xml->file" -d "$cache/update/$bundle/tmp"`;
308 |
309 | $valid = verifySignature( "$cache/update/$bundle/appcast.xml",
310 | "$cache/update/$bundle/$xml->file",
311 | "$dir/packal/$bundle.pub"
312 | );
313 |
314 | if ( ! $valid ) {
315 | echo "Error: Cannot verify signature for $xml->file from $bundle.";
316 | return false;
317 | }
318 |
319 | // Why can't I just include the function, call it, and be done with it?
320 | // I think it might be a namespacing issue or something.
321 | // migratePlist( "$dir/info.plist", "$cache/update/$bundle/tmp/info.plist" );
322 |
323 | // It's too late to figure that out. Maybe tomorrow.
324 | $cmd = 'php ' . __DIR__ . "/includes/plist-migration.php \"$dir/info.plist\" \"$cache/update/$bundle/tmp/info.plist\"";
325 | exec( "$cmd" );
326 |
327 | // Backup the bundle.
328 | echo `"$cliDir/packal.sh" backup "$bundle"`;
329 | $cmd = "'" . __DIR__ . "/packal.sh' replaceFiles " . escapeshellarg( $dir ) . ' ' . escapeshellarg( $cache . '/update/' . "$bundle/tmp/" );
330 |
331 | exec( "$cmd" );
332 |
333 | `rm -fR "$cache/update/$bundle"`;
334 |
335 | $tn = __load( 'terminal-notifier' , 'default' , 'utility' );
336 | exec( "$tn -title 'Packal Updater' -message '$xml->name has been updated to version $xml->version'" );
337 |
338 | echo 'TRUE';
339 | return true;
340 |
341 | }
342 |
343 | function doUpdateAll( $force = false ) {
344 | global $manifest, $cache, $cliDir;
345 |
346 | $xml = simplexml_load_file( "$manifest" );
347 | $me = getOption( array( 'username', true ) );
348 |
349 | foreach ( $xml as $w ) :
350 | $dir = trim( `"$cliDir/packal.sh" getDir "$w->bundle" 2> /dev/null` );
351 |
352 | if ( $dir === 'FALSE' ) {
353 | continue;
354 | }
355 |
356 | if ( "$w->author" == "$me" ) {
357 | continue;
358 | }
359 |
360 | if ( file_exists( "$dir/packal/package.xml" ) ) {
361 | $wf = simplexml_load_file( "$dir/packal/package.xml" );
362 | $wf->updated += 120; // Compensation for time in the generated packages.
363 |
364 | if ( "$w->version" != "$wf->version" ) {
365 | $updatable[] = array( (string) $w->name, (string) $wf->version, (string) $w->version, (string) $w->bundle );
366 | }
367 | } else {
368 | if ( $force == false ) {
369 | continue;
370 | }
371 |
372 | $updatable[] = array( (string) $w->name, 'Forced Update', (string) $w->version, (string) $w->bundle );
373 |
374 | }
375 |
376 | endforeach;
377 |
378 | if ( ( ! isset( $updatable ) ) || ( ! count( $updatable > 0 ) ) ) {
379 | return false;
380 | }
381 |
382 | foreach ( $updatable as $u ) :
383 | doUpdate( $u[3] );
384 | endforeach;
385 | }
386 |
387 | /**
388 | * Checks to the signature of a package
389 | * @param string $appcast an xml file containing the signature (path)
390 | * @param string $package a file that has been signed (path)
391 | * @param string $key the public key to use for checking (path)
392 | * @return [type] [description]
393 | */
394 | function verifySignature( $appcast, $package, $key ) {
395 |
396 | $appcast = simplexml_load_file( $appcast );
397 | $signature = $appcast->signature;
398 |
399 | $data = sha1_file( $package , false );
400 |
401 | // fetch public key from certificate and ready it
402 | $fp = fopen( $key , 'r' );
403 | $cert = fread( $fp , filesize( $key ) );
404 | fclose( $fp );
405 |
406 | // Get the public key
407 | $id = openssl_get_publickey( $cert );
408 |
409 | // Get the result of the signature
410 | $result = openssl_verify( $data , base64_decode( $signature ) , $id , OPENSSL_ALGO_SHA1 );
411 |
412 | // Free key from memory
413 | openssl_free_key( $id );
414 |
415 | // Return the result
416 | return $result;
417 |
418 | }
419 |
420 | ////////////////////////////////////////////////////////////////////////////////
421 | /// Strongarm functions
422 | // This isn't implemented currently. For the future.
423 | function forcePackal() {
424 | global $manifest, $cache;
425 |
426 | $xml = simplexml_load_file( "$manifest" );
427 | $me = getOption( array( 'username', true ) );
428 |
429 | }
430 |
--------------------------------------------------------------------------------
/cli/packal.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # important global variables
4 | bundle="com.packal"
5 | manifest="https://raw.github.com/packal/repository/master/manifest.xml"
6 | path="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd -P )"
7 |
8 | # Folders
9 | data="$HOME/Library/Application Support/Alfred 2/Workflow Data/$bundle"
10 | cache="$HOME/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/$bundle"
11 | backups="$data/backups"
12 | endpoints="$data/endpoints"
13 |
14 | # Utilities
15 | pb="/usr/libexec/PlistBuddy"
16 |
17 | ################################################################################
18 | # Functions
19 | ################################################################################
20 |
21 | setupDirs() {
22 | dir "$data"
23 | dir "$cache"
24 | dir "$backups"
25 | dir "$endpoints"
26 | }
27 |
28 | dir() {
29 | if [ ! -d "$1" ]; then
30 | mkdir "$1"
31 | fi
32 | }
33 |
34 | getManifest() {
35 | curl -sL "$manifest" > "$cache/manifest.xml"
36 | if [ `echo $?` = 0 ]; then
37 | if [ -f "$data/manifest.xml" ]; then
38 | rm "$data/manifest.xml"
39 | mv "$cache/manifest.xml" "$data/manifest.xml"
40 | else
41 | mv "$cache/manifest.xml" "$data/manifest.xml"
42 | fi
43 | else
44 | echo "Error: Server not reachable."
45 | fi
46 | echo "TRUE"
47 |
48 | }
49 |
50 | checkModified() {
51 | if [ -f "$1" ]; then
52 | echo `stat -f "%m" "$1"`
53 | else
54 | # File doesn't exist, so we'll just give it a 0 response.
55 | echo 0
56 | fi
57 | }
58 |
59 | isCacheValid() {
60 |
61 | # Set the TTL variable from argument, fallback to 24 hours.
62 | if [ -z "$1" ]; then
63 | local $ttl = 86400
64 | else
65 | local $ttl = $1
66 | fi
67 |
68 | # Check if modified within the TTL parameter
69 | if [ `checkModified "$data/manifest.xml"` -lt $ttl ]; then
70 | echo "FALSE"
71 | else
72 | echo "TRUE"
73 | fi
74 | }
75 |
76 | generateMap() {
77 | # Creates a map of bundles and directories.
78 | endpoints="$data/endpoints"
79 |
80 | if [ ! "$1" = "TRUE" ]; then
81 | if [[ ! `checkModified "$endpoints/endpoints.json"` -lt `stat -f "%m" "$path"` ]]; then
82 | # Nothing new has been installed, so there is no reason to update the map
83 | exit 0
84 | fi
85 | fi
86 |
87 | echo "{" > "$endpoints/endpoints.json"
88 | for w in "$path/"*
89 | do
90 | local bundle=`$pb -c "Print :bundleid" "$w/info.plist" 2> /dev/null`
91 | if [ ! -z "$bundle" ]; then
92 | echo "\"$bundle\": \"$w\"," >> "$endpoints/endpoints.json"
93 | fi
94 | done
95 |
96 | echo `cat "$endpoints/endpoints.json" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' | sed -e '$s|,$|}|'` > "$endpoints/endpoints.json"
97 |
98 | if [ -f "$endpoints/endpoints.list" ]; then
99 | rm "$endpoints/endpoints.list"
100 | fi
101 | for w in "$path/"*
102 | do
103 | local bundle=`$pb -c "Print :bundleid" "$w/info.plist" 2> /dev/null`
104 | if [ ! -z "$bundle" ]; then
105 | echo "\"$bundle\"=\"$w\"" >> "$endpoints/endpoints.list"
106 | fi
107 | done
108 |
109 | }
110 |
111 | getDir() {
112 | if [ ! -f "$endpoints/endpoints.list" ]; then
113 | generateMap
114 | fi
115 |
116 | line=`cat "$endpoints/endpoints.list" | grep "$1"`
117 | local bundle="$line"
118 |
119 | line=${line#*=}
120 | line=`echo $line | sed -e 's|\"||g'`
121 |
122 | bundle=${bundle%=*}
123 | bundle=`echo $bundle | sed -e 's|\"||g'`
124 |
125 | if [ "$bundle" = "$1" ]; then
126 | echo $line
127 | else
128 | echo "FALSE"
129 | fi
130 |
131 | }
132 |
133 | checkUpdate() {
134 | dir=`getDir "$1"`
135 | if [ -d "$dir/packal" ]; then
136 | echo "Packal WF"
137 | fi
138 | }
139 |
140 | getOpt() {
141 | dir=`getDir "$1"`
142 | echo `$pb -c "Print :$2" "$dir/info.plist"`
143 | }
144 |
145 | backup() {
146 |
147 | name=`getOpt "$1" "name"`
148 | dir=`getDir "$1"`
149 | date=`date +"%Y-%m-%d-%H.%M.%S"`
150 |
151 | file=`echo $date-$name.alfredworkflow | tr '&' '_' | tr ' ' '_'`
152 | cd "$dir"
153 | zip -q -r "$cache/$file" *
154 | cd -
155 | dir "$data/backups/$name"
156 |
157 | backups=`ls "$data/backups/$name" | grep alfredworkflow | wc -l`
158 | me="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd -P )"
159 |
160 | keep=`php "$me/cli/packal.php" getOption backups`
161 |
162 |
163 | if [[ $backups -ge $keep ]]; then
164 | count=$backups
165 | files=`ls "$data/backups/$name" | grep alfredworkflow`
166 | while [[ $count -gt $(( keep-1 )) ]]; do
167 | for f in $files; do
168 | if [[ $count -gt $(( keep-1 )) ]]; then
169 | f=`echo $f | sed 's|'\\\n'||g'`
170 | rm "$data/backups/$name/$f"
171 | count=$(( count-1 ))
172 | fi
173 | done
174 | done
175 | fi
176 |
177 | mv "$cache/$file" "$data/backups/$name/"
178 |
179 | }
180 |
181 | replaceFiles() {
182 | old="$1"
183 | new="$2"
184 | cd "$old"
185 | rm -fR *
186 | mv -f "$new"* .
187 | cd -
188 | }
189 |
190 | restoreBackup() {
191 | # Right now this function is empty.
192 | a=1
193 | }
194 |
195 | ################################################################################
196 | # Start Script
197 | ################################################################################
198 |
199 | setupDirs
200 |
201 | if [ "$1" = "update" ]; then
202 | if [ "$2" = "TRUE" ]; then
203 | getManifest
204 | generateMap TRUE
205 | else
206 | if [[ `checkModified "$data/manifest.xml"` -eq 0 ]]; then
207 | getManifest
208 | fi
209 | generateMap
210 | fi
211 |
212 | elif [ "$1" = "getDir" ]; then
213 | getDir "$2"
214 |
215 |
216 | elif [ "$1" = "checkUpdate" ]; then
217 | checkUpdate "$2"
218 |
219 | elif [ "$1" = "backup" ]; then
220 | backup "$2"
221 |
222 | elif [ "$1" = "replaceFiles" ]; then
223 | replaceFiles "$2" "$3"
224 |
225 | else
226 | echo "Error: invalid command ($1)"
227 | exit 1
228 |
229 | fi
230 |
231 | exit 0
232 |
--------------------------------------------------------------------------------
/config.php:
--------------------------------------------------------------------------------
1 | $val ) {
6 | $$var = $val;
7 | }
8 | $_SERVER['alfred_workflow_data'] = $data_dir;
9 | $_SERVER['alfred_workflow_cache'] = $cache_dir;
10 | $_SERVER['HOME'] = $HOME;
11 | $_SERVER['alfred_version'] = $alfred_version;
12 | $_SERVER['alfred_preferences'] = $alfred_preferences;
13 | }
14 |
15 | // These are just here for now...
16 | $bundle = isset( $_SERVER['alfred_workflow_bundleid'] ) ? $_SERVER['alfred_workflow_bundleid'] : 'com.packal';
17 | $home = $_SERVER['HOME'];
18 |
19 | function guess_alfred_version() {
20 | if ( isset( $_SERVER['alfred_version'] ) ) {
21 | return floor( floatval( $_SERVER['alfred_version'] ) );
22 | }
23 | if ( file_exists( '/Applications/Alfred 3.app' ) ) {
24 | return 3;
25 | }
26 | if ( file_exists( "{$_SERVER['HOME']}/Applications/Alfred 3.app" ) ) {
27 | return 3;
28 | }
29 | if ( file_exists( '/Applications/Alfred 2.app' ) ) {
30 | return 2;
31 | }
32 | if ( file_exists( "{$_SERVER['HOME']}/Applications/Alfred 2.app" ) ) {
33 | return 2;
34 | }
35 | throw new Exception( 'Cannot guess what version of Alfred to use' );
36 | }
37 |
38 | function data() {
39 | global $bundle, $home;
40 |
41 | if ( isset( $_SERVER['alfred_workflow_data'] ) ) {
42 | return $_SERVER['alfred_workflow_data'];
43 | }
44 |
45 | $v = guess_alfred_version();
46 | return "{$home}/Library/Application Support/Alfred {$v}/Workflow Data/{$bundle}";
47 | }
48 |
49 | function cache() {
50 | global $bundle, $home;
51 |
52 | if ( isset( $_SERVER['alfred_workflow_cache'] ) ) {
53 | return $_SERVER['alfred_workflow_cache'];
54 | }
55 |
56 | $v = guess_alfred_version();
57 | return "{$home}/Library/Caches/com.runningwithcrayons.Alfred-{$v}/Workflow Data/{$bundle}";
58 | }
59 |
60 | define( '__DATA__', data() );
61 | define( '__CACHE__', cache() );
62 | define( '__BUNDLE__', $bundle );
63 | define( '__HOME__', $home );
64 |
65 | $environments = [
66 | 'development' => 'http://localhost:3000', // Local Passenger Server
67 | 'dev-staging' => 'http://packal.dev', // Local nginx proxying to Passenger
68 | 'staging' => 'https://mellifluously.org', // Staging Server
69 | 'production' => 'https://www.packal.org', // Actual Production (not setup yet)
70 | ];
71 |
72 | // Turns on Development Code (extra logging, etc...)
73 | define( 'DEVELOPMENT_TESTING', true );
74 | define( '__LEGACY__', true );
75 |
76 | // The current environment is defined in environment.txt
77 | define( 'BUNDLE', 'com.packal' );
78 |
79 | define( 'CACHE', __CACHE__ );
80 | define( 'DATA', __DATA__ );
81 | define( 'ERROR_ICON', '/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/Unsupported.icns' );
82 |
83 | if ( ! isset( $_SERVER['alfred_workflow_cache'] ) ) {
84 | $_SERVER['alfred_workflow_cache'] = __CACHE__;
85 | }
86 | if ( ! isset( $_SERVER['alfred_workflow_data'] ) ) {
87 | $_SERVER['alfred_workflow_data'] = __DATA__;
88 | }
89 | if ( ! isset( $_SERVER['alfred_workflow_bundleid'] ) ) {
90 | $_SERVER['alfred_workflow_bundleid'] = $bundle;
91 | }
92 |
93 | foreach ( [ __CACHE__, __DATA__ ] as $dir ) :
94 | if ( ! file_exists( $dir ) ) {
95 | mkdir( $dir, 0775, true );
96 | }
97 | endforeach;
98 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/favicon.ico
--------------------------------------------------------------------------------
/functions.php:
--------------------------------------------------------------------------------
1 | ';
40 | $config = new SimpleXMLElement( $d );
41 | $config->packalAccount = 0;
42 | $config->forcePackal = 0;
43 | $config->backups = 3;
44 | $config->username = '';
45 | $config->authorName = '';
46 | $config->notifications = '2';
47 | $config->workflowReporting = '1';
48 | $config->apiKey = '';
49 | $config->asXML( "$data/config/config.xml" );
50 | unset( $config );
51 | }
52 |
53 | // Generate Empty Blacklist File
54 | if ( ! file_exists( "$data/config/blacklist.json" ) ) {
55 | file_put_contents( "$data/config/blacklist.json", utf8_encode( json_encode( array() ) ) );
56 | }
57 |
58 | if ( ! file_exists( "$data/manifest.xml" ) ) {
59 | // Get the manifest with error handling.
60 | if ( getManifest() == false ) {
61 | // So, we're getting the manifest, but
62 | // there was a problem, so we're going
63 | // to communicate that.
64 | return false;
65 | }
66 | }
67 | return true;
68 | }
69 |
70 | function generateEndpoints( $force = false ) {
71 | global $bundle;
72 |
73 | $HOME = exec( 'echo $HOME' );
74 | $data = DATA_DIR;
75 |
76 | if ( ! file_exists( "$data/endpoints" ) && is_dir( "$data/endpoints" ) ) {
77 | mkdir( "$data/endpoints" );
78 | }
79 |
80 | if ( ( ! ( file_exists( "$data/endpoints/endpoints.json" ) && file_exists( "$data/endpoints/endpoints.list" ) ) )
81 | || ( filemtime( "$data/endpoints/endpoints.json" ) < filemtime( dirname( __DIR__ ) ) ) || ( $force !== false ) ) {
82 |
83 | // Okay, we need to update the files.
84 | $dirs = array_diff( scandir( WORKFLOWS_DIR ), array( '.', '..', '.git', '.DS_Store' ) );
85 |
86 | if ( file_exists( "$data/endpoints/endpoints.list" ) ) {
87 | unlink( "$data/endpoints/endpoints.list" );
88 | }
89 | $fp = fopen( "$data/endpoints/endpoints.list", 'w' );
90 |
91 | $me = basename( __DIR__ );
92 |
93 | foreach ( $dirs as $d ) :
94 | $d = str_replace( '//', '/', str_replace( $me, '', __DIR__ ) . "/$d" );
95 | $bundle = readPlistValue( 'bundleid', "$d/info.plist" );
96 | if ( empty( $bundle ) ) {
97 | continue;
98 | }
99 |
100 | $endpoints[ $bundle ] = $d;
101 | fwrite( $fp , "\"$bundle\"=\"$d\"\n" );
102 | endforeach;
103 |
104 | file_put_contents( "$data/endpoints/endpoints.json", utf8_encode( json_encode( $endpoints ) ) );
105 | fclose( $fp );
106 | } else { return false;
107 | }
108 | }
109 |
110 | function readPlistValue( $key, $plist ) {
111 | return exec( "/usr/libexec/PlistBuddy -c \"Print :$key\" '$plist' 2> /dev/null" );
112 | }
113 |
114 | function checkConnection() {
115 | ini_set( 'default_socket_timeout', 1 );
116 |
117 | // First test
118 | exec( 'ping -c 1 -t 1 www.github.com', $pingResponse, $pingError );
119 | if ( $pingError == 14 ) {
120 | return false;
121 | }
122 |
123 | // Second Test
124 | $connection = @fsockopen( 'www.github.com', 80, $errno, $errstr, 1 );
125 |
126 | if ( $connection ) {
127 | $status = true;
128 | fclose( $connection );
129 | } else {
130 | $status = false;
131 | }
132 | return $status;
133 | }
134 |
135 | function countFiles( $dir ) {
136 | $fi = new FilesystemIterator( "$dir" , FilesystemIterator::SKIP_DOTS );
137 | return iterator_count( $fi );
138 | }
139 |
140 | function getFiles( $dir ) {
141 | return array_diff( scandir( $dir ), array( '..', '.', '.DS_Store' ) );
142 | }
143 |
144 | function returnBackups( $dir, &$w ) {
145 | global $data;
146 |
147 | $backupDirs = getFiles( "$data/backups" );
148 | foreach ( $backupDirs as $b ) :
149 | if ( is_dir( "$data/backups/$b" ) ) {
150 | $backups[ $b ] = countFiles( "$data/backups/$b" );
151 | }
152 | endforeach;
153 |
154 | if ( count( $backups ) > 0 ) {
155 | ksort( $backups );
156 | foreach ( $backups as $name => $count ) :
157 | $w->result( '', '', $name, "$count backups.", '', 'no', '' );
158 | endforeach;
159 | }
160 | }
161 |
162 | function getManifestModTime() {
163 | global $data;
164 |
165 | // Set date/time things here.
166 | $m = time() - filemtime( "$data/manifest.xml" );
167 | $days = floor( $m / 86400 );
168 | $hours = floor( ( $m - ( $days * 86400 ) ) / 3600 );
169 | $mins = floor( ( $m - ( $hours * 3600 ) ) / 60 );
170 | $secs = floor( $m % 60 );
171 |
172 | if ( $m > 60 * 60 * 24 * 7 * 120 ) {
173 | return 'a really long time ago.';
174 | }
175 | if ( $m > 60 * 60 * 24 * 7 * 30 ) {
176 | return 'over a month ago.';
177 | }
178 | if ( $m > 60 * 60 * 24 * 7 * 30 ) {
179 | return 'over a week ago.';
180 | }
181 | if ( $m > 60 * 60 * 24 ) {
182 | return 'over a day ago.';
183 | }
184 | if ( $m === 0 ) {
185 | $time = 'just now.';
186 | }
187 | $time = '';
188 | if ( $hours > 0 ) {
189 | $time .= $hours . ' hour';
190 | if ( $hours > 1 ) {
191 | $time .= 's, ';
192 | } else { $time .= ', ';
193 | }
194 | }
195 | if ( $mins > 0 ) {
196 | $time .= $mins . ' minute';
197 | if ( $mins > 1 ) {
198 | $time .= 's';
199 | } else { $time .= '';
200 | }
201 | }
202 | if ( $hours > 0 && $mins > 0 ) {
203 | $time .= ', and ';
204 | } elseif ( $hours > 0 || $mins > 0 ) {
205 | $time .= ' and ';
206 | }
207 | if ( $secs > 0 ) {
208 | $time .= $secs . ' second';
209 | if ( $time > 1 ) {
210 | $time .= 's';
211 | }
212 | }
213 | $time .= ' ago.';
214 |
215 | return $time;
216 | }
217 |
218 | function sortWorkflowByName( $a, $b ) {
219 | return $a['name'] > $b['name'];
220 | }
221 |
--------------------------------------------------------------------------------
/gui/assets/css/font-awesome.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome 4.1.0 by @davegandy - http://fontawesome.io - @fontawesome
3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
4 | */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.1.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@keyframes spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-square:before,.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}
--------------------------------------------------------------------------------
/gui/assets/css/normalize.css:
--------------------------------------------------------------------------------
1 | article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block;}audio,canvas,video{display:inline-block;}audio:not([controls]){display:none;height:0;}[hidden]{display:none;}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;}body{margin:0;}a:focus{outline:thin dotted;}a:active,a:hover{outline:0;}h1{font-size:2em;margin:0.67em 0;}abbr[title]{border-bottom:1px dotted;}b,strong{font-weight:bold;}dfn{font-style:italic;}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0;}mark{background:#ff0;color:#000;}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em;}pre{white-space:pre-wrap;}q{quotes:"\201C" "\201D" "\2018" "\2019";}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sup{top:-0.5em;}sub{bottom:-0.25em;}img{border:0;}svg:not(:root){overflow:hidden;}figure{margin:0;}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em;}legend{border:0;padding:0;}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0;}button,input{line-height:normal;}button,select{text-transform:none;}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}button[disabled],html input[disabled]{cursor:default;}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none;}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}textarea{overflow:auto;vertical-align:top;}table{border-collapse:collapse;border-spacing:0;}
--------------------------------------------------------------------------------
/gui/assets/css/style.css:
--------------------------------------------------------------------------------
1 | html {
2 | font-size: 12px;
3 | font-family: 'Source Sans Pro', Georgia;
4 | line-height: 16px;
5 | margin: none;
6 | padding: none;
7 | }
8 |
9 | body {
10 | background: rgba(233, 233, 233, .5);
11 | user-select: none;
12 | -webkit-user-select: none;
13 | }
14 |
15 | pre {
16 | white-space: pre-wrap;
17 | }
18 |
19 | h1, h2, h3, h4, h5, h6 {
20 | font-family: 'Montserrat';
21 | color: #333;
22 | }
23 |
24 | .title h1 {
25 | color: purple;
26 | }
27 |
28 | table tr:nth-child(even) {
29 | background: rgba(0,0,0,0.1);
30 | }
31 |
32 | a {
33 | position: relative;
34 | margin: -.5em;
35 | padding: .5em;
36 | color: #08C;
37 | text-decoration: none;
38 | transition: all 0.3s ease-out;
39 | }
40 | a:hover { color: #0AF; }
41 |
42 | *, *:before, *:after {
43 | -webkit-box-sizing: border-box;
44 | box-sizing: border-box;
45 | }
46 |
47 | code {
48 | font-family: Monaco;
49 | font-size: .75em;
50 | font-weight: 300;
51 | }
52 | .clearfix:before,
53 | .clearfix:after {
54 | display: table;
55 | content: " ";
56 | }
57 |
58 | .clearfix:after {
59 | clear: both;
60 | }
61 |
62 | /*******************************************************************************
63 | General Layout
64 | *******************************************************************************/
65 | .viewport {
66 | position: fixed;
67 | width: 100%;
68 | min-width: 600px;
69 | height: 100%;
70 | background: rgba(253, 253, 253, .5);
71 | }
72 |
73 | .header {
74 | position: relative;
75 | padding-bottom: 20px;
76 | max-height: 100px;
77 | width: inherit;
78 | height: 17%;
79 | min-width: 600px;
80 | border-bottom: 5px #900080 solid !important;
81 | padding: 0 10px 0 35px;
82 | }
83 |
84 | .pane {
85 | overflow: scroll;
86 | width: 100%;
87 | height: 83%;
88 | border-top: 4px solid black;
89 | padding: 2em 35px 3em 35px;
90 | }
91 |
92 | .preloader {
93 | padding: 10% 0 0 48%;
94 | width: 100%;
95 | height: 100%;
96 | }
97 |
98 | .preloader h2 {
99 | margin-bottom: 28px;
100 | margin-left: -32px;
101 | color: black;
102 | }
103 |
104 | #updating-overlay {
105 | position: fixed;
106 | display: none;
107 | margin: 0 25%;
108 | z-index: 200;
109 | width: 45%;
110 | height: 30%;
111 | min-height: 400px;
112 | border: 5px solid black;
113 | background-color: #efefef;
114 | text-align: center;
115 | opacity: .8;
116 | top: 15%;
117 | }
118 |
119 | #updating-overlay h2 {
120 | color: black;
121 | margin-top: 20%;
122 | }
123 |
124 | .box {
125 | position: relative;
126 | z-index: 0;
127 | float: left;
128 | margin: 1em;
129 | padding: 1em;
130 | width: 30%;
131 | height: 200px;
132 | border: 1px black solid;
133 | }
134 |
135 | .disabled {
136 | opacity: 0.5;
137 | pointer-events: none;
138 | }
139 |
140 | .header h1 {
141 | margin: 10px 0 0 0;
142 | font-size: 3em;
143 | }
144 |
145 | .title {
146 | padding: 2em 0 0 0em;
147 | height: 100%;
148 | }
149 |
150 | .author {
151 | content: 'Me.';
152 | }
153 |
154 | .wficon {
155 | z-index: 0;
156 | width: 72px;
157 | height: 72px;
158 | }
159 |
160 | .wficon-container {
161 | position: absolute;
162 | bottom: 17px;
163 | padding-right: 25px;
164 | width: 100%;
165 | text-align: right;
166 | }
167 |
168 | .separator {
169 | margin: 0;
170 | width: 100%;
171 | height: 3px;
172 | border: 0px;
173 | background: black;
174 | text-align: center;
175 | }
176 |
177 | .blacklisted {
178 | position: absolute;
179 | z-index: 1000;
180 | margin: -1em 0 0 -1em;
181 | width: 100%;
182 | height: 100%;
183 | background: #ccc;
184 | opacity: .3;
185 | display: block;
186 | text-align: center;
187 | padding: 0;
188 | }
189 |
190 | .disabled-x {
191 | /*float: left;*/
192 |
193 | font-size: 18em;
194 | /*margin: 0 30%;*/
195 | }
196 | /*'line-height: 190px; font-size: 250px; padding-left: 20%;'*/
197 |
198 | .hide {
199 | display: none;
200 | }
201 |
202 | .blist, .open-directory, #open-backup-dir {
203 | cursor: pointer;
204 | }
205 |
206 | .icon {
207 | margin-right: 1em;
208 | margin-bottom: 1em;
209 | width: 24px;
210 | }
211 |
212 | .nav > ul > li > div > div {
213 | position: relative;
214 | float: left;
215 |
216 | }
217 |
218 | .nav > ul > li > div {
219 | padding: .25em;
220 | min-height: 20px;
221 | border-top: 1px black solid;
222 | }
223 |
224 | .nav ul li {
225 | clear: both;
226 | margin: 1em 1em;
227 | list-style: none;
228 | line-height: 24px;
229 |
230 | }
231 |
232 | .short {
233 | float: left;
234 | overflow: hidden;
235 | padding: 0;
236 | max-width: 100%;
237 | height: 3em;
238 | text-overflow: ellipsis;
239 | white-space: nowrap;
240 | }
241 | .short p {
242 | overflow: hidden;
243 | margin: 0;
244 | height: 3em;
245 | text-overflow: ellipsis;
246 | }
247 |
248 | .backups li {
249 | margin: 1em;
250 | list-style: none;
251 | font-size: 1.2em;
252 |
253 | }
254 |
255 | .backup-box h2 {
256 | color: black;
257 | }
258 |
259 | .backup-box {
260 | border-color: black;
261 | }
262 |
263 | .delete-backup {
264 | cursor: pointer;
265 | }
266 |
267 | .open-backup-dir h3 {
268 | color: black;
269 | cursor: pointer;
270 | }
271 |
272 | .open-directory:hover {
273 | color: #800080;
274 | transition: color .25s;
275 | }
276 |
277 | .open-directory {
278 | color: black;
279 | margin-left: .5em;
280 | transition: color .25s;
281 | }
282 |
283 | /**** Dialogs ****/
284 | .ui-dialog {
285 | border: 4px solid black;
286 | border-top: 5px solid black;
287 | padding: 1em 3em;
288 | width: auto;
289 | max-width: 100%;
290 | background: rgba(233, 233, 233, 1);
291 | }
292 |
293 | .ui-dialog-titlebar, .ui-dialog-titlebar-close, .ui-dialog-title {
294 | display: none;
295 | }
296 |
297 | .ui-dialog-content {
298 | text-align: center;
299 | font-size: 2em;
300 | line-height: 1em;
301 | padding: .5em 0 0 0;
302 | font-family: 'Source Sans Pro';
303 | }
304 |
305 | #delete-backup-dialog {
306 | font-size: 1.5em;
307 | }
308 |
309 | .ui-dialog-buttonpane {
310 | text-align: right;
311 | }
312 |
313 | .ui-dialog-buttonset {
314 | outline: none;
315 | }
316 |
317 | .ui-dialog-buttonset button {
318 | outline: none;
319 | background: none;
320 | font-size: 1.5em;
321 | border-radius:6px;
322 | border: 3px solid black;
323 | padding: .15em 1em .25em 1em;
324 | margin: 0 1em 0 0;
325 | background: #800080;
326 | color: #efefef;
327 | transition: background .25s,color .25s;
328 | }
329 |
330 | .ui-dialog-buttonset button:hover {
331 | background: #efefef;
332 | color: #800080;
333 | transition: background .25s,color .25s;
334 | }
335 |
336 | .fa {
337 | opacity: .8;
338 | }
339 |
340 |
341 |
342 | .delete-backup:hover {
343 | color: #A60000;
344 | -webkit-transition: color .25s ease-in;
345 | transition: color .25s ease-in;
346 | }
347 |
348 | /*******************************************************************************
349 | * Status
350 | *******************************************************************************/
351 | .updates-available {
352 | cursor: pointer
353 | }
354 | .detail-accordion > h3 {
355 | margin-bottom: 1em;
356 | margin-left: 2em;
357 | padding: 2px 0;
358 | max-width: 75px;
359 | border-top: 1px dashed black;
360 | border-bottom: 1px dashed black;
361 | color: gray;
362 | text-align: center;
363 | letter-spacing: 1px;
364 | font-weight: normal;
365 | font-size: 1em !important;
366 | font-family: 'Montserrat', Georgia !important;
367 | line-height: 1.2em;
368 | cursor: pointer;
369 | }
370 | .detail-accordion > div > div, .detail-accordion > p {
371 | position: relative;
372 | float: left;
373 | clear: both;
374 | margin: .25em 0 1em 2.5em;
375 | padding: .75em 1em;
376 | width: 600px;
377 | border: 1px solid black;
378 | font-size: .75em;
379 | line-height: 1.5em;
380 | }
381 |
382 | .ui-accordion .ui-accordion-content{
383 | overflow: auto;
384 | }
385 |
386 | .url-open, .update-manifest {
387 | clear: none !important;
388 | width: 90px;
389 | border: none !important;
390 | border-bottom: 1px gray dashed !important;
391 | color: gray;
392 | cursor: pointer;
393 | }
394 |
395 | .update-manifest {
396 | width: 126px !important;
397 | border: none !important;
398 | border-bottom: 1px gray dashed !important;
399 | color: gray;
400 | cursor: pointer;
401 | }
402 |
403 | .status-body {
404 | margin: 3em 0 0 2%;
405 | min-width: 600px;
406 | width: 95%;
407 | font-size: 1.5em;
408 | }
409 |
410 | .status-body > div {
411 | margin-bottom: 1em;
412 | }
413 |
414 | /*******************************************************************************
415 | * About
416 | ******************************************************************************/
417 |
418 | #about-section {
419 | width: 95%;
420 | font-size: 1.5em;
421 | line-height: 1.5em;
422 | }
423 |
424 | #about-section p {
425 | margin-left: 2em;
426 | }
427 |
428 | /*******************************************************************************
429 | * Updates
430 | ******************************************************************************/
431 |
432 | .updates-complete-backdrop {
433 | position: absolute;
434 | clear: none;
435 | width: 93%;
436 | height: 60%;
437 | background: url( '../../assets/images/packal-man.jpg' ) no-repeat center;
438 | background-size: contain;
439 | opacity: .25;
440 | }
441 |
442 | .center-me-please {
443 | float: left;
444 | width: 100%;
445 | padding: 15%;
446 | display: table-cell;
447 | text-align: center;
448 | font-size: 1.5em;
449 | line-height: 2em;
450 | vertical-align: middle;
451 | }
452 |
453 | .update-box {
454 | margin: 25px 0 0 2%;
455 | padding: .1em;
456 | width: 90%;
457 | height: 110px;
458 | border: 1px solid black;
459 | }
460 |
461 | .update-icon {
462 | position: relative;
463 | display: inline-block;
464 | float: left;
465 | padding: 25px 0;
466 | width: 125px;
467 | height: 110px;
468 | text-align: center;
469 | opacity: .9;
470 |
471 | }
472 |
473 | .update-icon img {
474 | max-width: 48px;
475 | }
476 |
477 | .update-content {
478 | position: relative;
479 | float: left;
480 | }
481 |
482 | .update-button {
483 | /*border: 2px black solid;*/
484 | /*font-size: 1.5em;*/
485 | float: right;
486 | margin: 1em 1em 0 0;
487 | padding: 15px 50px 0 0;
488 | /*width: 100px;*/
489 | height: 110px;
490 | text-align: center;
491 | }
492 |
493 | .update-box button:focus {
494 | outline: none;
495 | }
496 |
497 | button.css3button {
498 | padding: 10px 20px;
499 | border: 3px solid black;
500 | background: #800080;
501 | color: #e6e6e6;
502 | font-size: 1.25em;
503 | transition: background .25s, color .25s, border-color .25s;
504 | }
505 |
506 | button.css3button:hover {
507 | background: #ccc;
508 | color: black;
509 | border-color: black;
510 | transition: background .25s, color .25s, border-color .25s;
511 | }
512 |
513 | /*******************************************************************************
514 | Backups
515 | *******************************************************************************/
516 |
517 | .backup-box {
518 | margin: 25px 0 0 2%;
519 | padding: 1em;
520 | width: 90%;
521 | border: 1px solid black;
522 | }
523 |
524 | /*******************************************************************************
525 | Settings
526 | *******************************************************************************/
527 | /* general style for the form */
528 | .settings-form {
529 | margin: 0.3em auto 0 auto;
530 | width: 95%;
531 | font-size: 1.5em;
532 | line-height: 2em;
533 | }
534 |
535 | .firstRun {
536 | font-size: 1.5em;
537 | margin: 2em 0 -1em 2em;
538 | background: #ddd;
539 | width: 40em;
540 | padding: .25em 2em;
541 | text-align: center;
542 | border: 3px dashed gray;
543 | }
544 |
545 | /* normalize the input elements, make them look like everything else */
546 | .settings-form input,
547 | .settings-form select,
548 | .settings-form button {
549 | display: inline-block;
550 | margin: 0;
551 | padding: 0;
552 | border: none;
553 | background: transparent;
554 | color: inherit;
555 | font-weight: inherit;
556 | font-size: inherit;
557 | font-family: inherit;
558 | line-height: inherit;
559 | -webkit-appearance: none;
560 | }
561 |
562 | .settings-form input:focus {
563 | outline: none;
564 | }
565 |
566 | .settings-form input,
567 | .settings-form select {
568 | display: inline-block;
569 | margin: 0 .25em;
570 | padding: 0;
571 | border-bottom: 1px dashed #b14943;
572 | /*color: #b14943;*/
573 | color: purple;
574 | line-height: 1.2em;
575 | cursor: pointer;
576 | }
577 |
578 | /* These are blank spans to help resize form elements. */
579 | #username,
580 | #authorName,
581 | #packal-username,
582 | #number-of-backups,
583 | #workflow-reporting,
584 | #force-packal,
585 | #notification-options {
586 | display: none;
587 | }
588 |
589 | /*******************************************************************************
590 | Tooltips
591 | *******************************************************************************/
592 | .ui-tooltip, .arrow:after {
593 | background-color: rgba(128, 0, 128, 0.8);
594 | border: 2px solid #cfcfcf;
595 | }
596 | .ui-tooltip {
597 | padding: 10px 10px;
598 | color: white;
599 | border-radius: 20px;
600 | max-width: 20em;
601 | text-align: justify;
602 | /*font: bold 14px "Helvetica Neue", Sans-Serif;*/
603 | /*text-transform: uppercase;*/
604 | box-shadow: 0 0 3px black;
605 | }
606 | .arrow {
607 | width: 70px;
608 | height: 16px;
609 | overflow: hidden;
610 | position: absolute;
611 | left: 50%;
612 | margin-left: -35px;
613 | bottom: -16px;
614 | }
615 | .arrow.top {
616 | top: -16px;
617 | bottom: auto;
618 | }
619 | .arrow.left {
620 | left: 20%;
621 | }
622 | .arrow:after {
623 | content: "";
624 | position: absolute;
625 | left: 20px;
626 | top: -20px;
627 | width: 25px;
628 | height: 25px;
629 | box-shadow: 6px 5px 9px -9px black;
630 | -webkit-transform: rotate(45deg);
631 | -moz-transform: rotate(45deg);
632 | -ms-transform: rotate(45deg);
633 | -o-transform: rotate(45deg);
634 | tranform: rotate(45deg);
635 | }
636 | .arrow.top:after {
637 | bottom: -20px;
638 | top: auto;
639 | }
640 |
641 |
642 |
643 | /*******************************************************************************
644 | Menu
645 | *******************************************************************************/
646 |
647 | .bt-menu {
648 | position: fixed;
649 | top: 0;
650 | left: 0;
651 | width: 100%;
652 | min-width: 600px;
653 | height: 0;
654 | border-width: 0px;
655 | border-style: solid;
656 | border-color: #333;
657 | background-color: rgba(0,0,0,0);
658 | -webkit-transition: border-width 0.3s, background-color 0.3s, height 0s 0.3s;
659 | transition: border-width 0.3s, background-color 0.3s, height 0s 0.3s;
660 | -webkit-backface-visibility: hidden;
661 | }
662 |
663 | .bt-menu.bt-menu-open {
664 | height: 100%;
665 | border-width: 90px 30px 30px 30px;
666 | background-color: rgba(0,0,0,0.3);
667 | -webkit-transition: border-width 0.3s, background-color 0.3s;
668 | transition: border-width 0.3s, background-color 0.3s;
669 | }
670 |
671 | .bt-menu-open {
672 | z-index: 1000;
673 | }
674 |
675 | .bt-overlay {
676 | position: absolute;
677 | width: 100%;
678 | min-width: 600px;
679 | }
680 |
681 | .bt-menu-open .bt-overlay {
682 | height: 100%;
683 | }
684 |
685 | .bt-menu-trigger {
686 | position: fixed;
687 | top: 22px;
688 | left: 50%;
689 | z-index: 100;
690 | display: block;
691 | margin-left: -25px;
692 | width: 50px;
693 | height: 50px;
694 | cursor: pointer;
695 | }
696 |
697 | .bt-menu-trigger span {
698 | position: absolute;
699 | top: 50%;
700 | left: 0;
701 | display: block;
702 | width: 100%;
703 | height: 8%;
704 | background-color: purple;
705 | font-size: 0px;
706 | -webkit-transition: background-color 0.3s;
707 | transition: background-color 0.3s;
708 | -webkit-touch-callout: none;
709 | -webkit-user-select: none;
710 | user-select: none;
711 | }
712 |
713 | .bt-menu-open .bt-menu-trigger span {
714 | background-color: #fff;
715 | }
716 |
717 | .bt-menu-trigger span:before,
718 | .bt-menu-trigger span:after {
719 | position: absolute;
720 | left: 0;
721 | width: 100%;
722 | height: 100%;
723 | background: purple;
724 | content: '';
725 | -webkit-transition: -webkit-transform 0.3s, background-color 0.3s;
726 | transition: transform 0.3s, background-color 0.3s;
727 | }
728 |
729 | .bt-menu-trigger span:before {
730 | -webkit-transform: translateY(-250%);
731 | transform: translateY(-250%);
732 | }
733 |
734 | .bt-menu-trigger span:after {
735 | -webkit-transform: translateY(250%);
736 | transform: translateY(250%);
737 | }
738 |
739 | .bt-menu-open .bt-menu-trigger span:before,
740 | .bt-menu-open .bt-menu-trigger span:after {
741 | background-color: #fff;
742 | }
743 |
744 | .bt-menu-open .bt-menu-trigger span:before {
745 | -webkit-transform: translateY(-350%);
746 | transform: translateY(-350%);
747 | }
748 |
749 | .bt-menu-open .bt-menu-trigger span:after {
750 | -webkit-transform: translateY(350%);
751 | transform: translateY(350%);
752 | }
753 |
754 | .bt-menu ul {
755 | position: fixed;
756 | top: 0px;
757 | left: 0;
758 | margin: 0;
759 | padding: 0;
760 | width: 100%;
761 | height: 0;
762 | list-style: none;
763 | text-align: center;
764 | white-space: nowrap;
765 | -webkit-transition: height 0s 0.3s;
766 | transition: height 0s 0.3s;
767 | }
768 |
769 | .bt-menu.bt-menu-open ul {
770 | height: 90px;
771 | -webkit-transition: none;
772 | transition: none;
773 | }
774 |
775 | .bt-menu ul li,
776 | .bt-menu ul li a {
777 | text-align: center;
778 | }
779 |
780 | .bt-menu ul li {
781 | display: inline-block;
782 | margin: 0 2%;
783 | width: 5%;
784 | height: 90px;
785 | line-height: 90px;
786 | opacity: 0;
787 | -webkit-transition: -webkit-transform 0.3s, opacity 0.3s;
788 | transition: transform 0.3s, opacity 0.3s;
789 | -webkit-transform: translate3d(0,-100%,0);
790 | transform: translate3d(0,-100%,0);
791 | }
792 |
793 | .bt-menu ul li:nth-child(3) {
794 | margin-right: 70px;
795 | }
796 |
797 | .bt-menu ul li:nth-child(4) {
798 | margin-left: 70px;
799 | }
800 |
801 | .bt-menu.bt-menu-open ul li {
802 | opacity: 1;
803 | -webkit-transform: translate3d(0,0,0);
804 | transform: translate3d(0,0,0);
805 | }
806 |
807 | .bt-menu.bt-menu-open ul li:first-child,
808 | .bt-menu.bt-menu-open ul li:last-child {
809 | -webkit-transition-delay: 0.15s;
810 | transition-delay: 0.15s;
811 | }
812 |
813 | .bt-menu.bt-menu-open ul li:nth-child(2),
814 | .bt-menu.bt-menu-open ul li:nth-last-child(2) {
815 | -webkit-transition-delay: 0.1s;
816 | transition-delay: 0.1s;
817 | }
818 |
819 | .bt-menu.bt-menu-open ul li:nth-child(3),
820 | .bt-menu.bt-menu-open ul li:nth-last-child(3) {
821 | -webkit-transition-delay: 0.05s;
822 | transition-delay: 0.05s;
823 | }
824 |
825 | .bt-menu ul li a {
826 | display: block;
827 | outline: none;
828 | color: #fff;
829 | text-decoration: none;
830 | text-transform: uppercase;
831 | letter-spacing: 1px;
832 | font-size: 1.15em;
833 | -webkit-transition: color 0.2s;
834 | transition: color 0.2s;
835 | }
836 |
837 | .bt-menu ul li a:before {
838 | display: none;
839 | font-size: 32px;
840 | }
841 |
842 | .bt-menu ul li a:hover,
843 | .bt-menu ul li a:focus {
844 | color: #2980b9;
845 | }
846 |
847 | /************ /MENU *************/
848 |
849 | #fusion_ad {
850 | font-size: .7em;
851 | max-width: 135px;
852 | position: absolute;
853 | right: 5em;
854 | }
855 | .fusionentire > a {
856 | clear: both;
857 | display: inline-block;
858 |
859 | }
860 | .fusionimg {
861 | margin-bottom: 5px;
862 | }
863 | .bsap {
864 | margin-top: 2px;
865 | margin-bottom: 1em;
866 | }
--------------------------------------------------------------------------------
/gui/assets/fonts/Montserrat/IQHow_FEYlDC4Gzy_m8fcnbFhgvWbfSbdVg11QabG8w.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Montserrat/IQHow_FEYlDC4Gzy_m8fcnbFhgvWbfSbdVg11QabG8w.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/Montserrat/montserrat.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Montserrat';
3 | font-style: normal;
4 | font-weight: 400;
5 | src: local('Montserrat-Regular'), url('zhcz-_WihjSQC0oHJ9TCYL3hpw3pgy2gAi-Ip7WPMi0.woff') format('woff');
6 | }
7 | @font-face {
8 | font-family: 'Montserrat';
9 | font-style: normal;
10 | font-weight: 700;
11 | src: local('Montserrat-Bold'), url('IQHow_FEYlDC4Gzy_m8fcnbFhgvWbfSbdVg11QabG8w.woff') format('woff');
12 | }
13 |
--------------------------------------------------------------------------------
/gui/assets/fonts/Montserrat/zhcz-_WihjSQC0oHJ9TCYL3hpw3pgy2gAi-Ip7WPMi0.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Montserrat/zhcz-_WihjSQC0oHJ9TCYL3hpw3pgy2gAi-Ip7WPMi0.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/Source Sans Pro/M2Jd71oPJhLKp0zdtTvoM_bce-VcyLJMRR1FC9qWbU8.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Source Sans Pro/M2Jd71oPJhLKp0zdtTvoM_bce-VcyLJMRR1FC9qWbU8.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/Source Sans Pro/ODelI1aHBYDBqgeIAH2zlNHq-FFgoDNV3GTKpHwuvtI.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Source Sans Pro/ODelI1aHBYDBqgeIAH2zlNHq-FFgoDNV3GTKpHwuvtI.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6H7XMO6S-yJpg1torQFmnv33rGVtsTkPsbDajuO5ueQw.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6H7XMO6S-yJpg1torQFmnv33rGVtsTkPsbDajuO5ueQw.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6J4LxuTxC3JbLqy8IUt0K1T3rGVtsTkPsbDajuO5ueQw.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6J4LxuTxC3JbLqy8IUt0K1T3rGVtsTkPsbDajuO5ueQw.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6MJvEBP8Mx4XcuTrPnlPwTr3rGVtsTkPsbDajuO5ueQw.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6MJvEBP8Mx4XcuTrPnlPwTr3rGVtsTkPsbDajuO5ueQw.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6OE3EfhCMemg4BxrY2mmJD_3rGVtsTkPsbDajuO5ueQw.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6OE3EfhCMemg4BxrY2mmJD_3rGVtsTkPsbDajuO5ueQw.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6PgYMAt3u4NmhhzLLLPJ5qH3rGVtsTkPsbDajuO5ueQw.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6PgYMAt3u4NmhhzLLLPJ5qH3rGVtsTkPsbDajuO5ueQw.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/Source Sans Pro/source.sans.pro.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Source Sans Pro';
3 | font-style: normal;
4 | font-weight: 200;
5 | src: url('toadOcfmlt9b38dHJxOBGC-IiwWNzQT_LXAtr-Ee9Pw.woff') format('woff');
6 | }
7 | @font-face {
8 | font-family: 'Source Sans Pro';
9 | font-style: normal;
10 | font-weight: 300;
11 | src: url('toadOcfmlt9b38dHJxOBGMVNtom4QlEDNJaqqqzqdSs.woff') format('woff');
12 | }
13 | @font-face {
14 | font-family: 'Source Sans Pro';
15 | font-style: normal;
16 | font-weight: 400;
17 | src: url('ODelI1aHBYDBqgeIAH2zlNHq-FFgoDNV3GTKpHwuvtI.woff') format('woff');
18 | }
19 | @font-face {
20 | font-family: 'Source Sans Pro';
21 | font-style: normal;
22 | font-weight: 600;
23 | src: url('toadOcfmlt9b38dHJxOBGCmgpmuQqK2I-L2S9cF65Ek.woff') format('woff');
24 | }
25 | @font-face {
26 | font-family: 'Source Sans Pro';
27 | font-style: normal;
28 | font-weight: 700;
29 | src: url('toadOcfmlt9b38dHJxOBGIqjGYJUyOXcBwUQbRaNH6c.woff') format('woff');
30 | }
31 | @font-face {
32 | font-family: 'Source Sans Pro';
33 | font-style: normal;
34 | font-weight: 900;
35 | src: url('toadOcfmlt9b38dHJxOBGC7eGk4PJkA83J1AXCmgUfc.woff') format('woff');
36 | }
37 | @font-face {
38 | font-family: 'Source Sans Pro';
39 | font-style: italic;
40 | font-weight: 200;
41 | src: url('fpTVHK8qsXbIeTHTrnQH6OE3EfhCMemg4BxrY2mmJD_3rGVtsTkPsbDajuO5ueQw.woff') format('woff');
42 | }
43 | @font-face {
44 | font-family: 'Source Sans Pro';
45 | font-style: italic;
46 | font-weight: 300;
47 | src: url('fpTVHK8qsXbIeTHTrnQH6H7XMO6S-yJpg1torQFmnv33rGVtsTkPsbDajuO5ueQw.woff') format('woff');
48 | }
49 | @font-face {
50 | font-family: 'Source Sans Pro';
51 | font-style: italic;
52 | font-weight: 400;
53 | src: url('M2Jd71oPJhLKp0zdtTvoM_bce-VcyLJMRR1FC9qWbU8.woff') format('woff');
54 | }
55 | @font-face {
56 | font-family: 'Source Sans Pro';
57 | font-style: italic;
58 | font-weight: 600;
59 | src: url('fpTVHK8qsXbIeTHTrnQH6J4LxuTxC3JbLqy8IUt0K1T3rGVtsTkPsbDajuO5ueQw.woff') format('woff');
60 | }
61 | @font-face {
62 | font-family: 'Source Sans Pro';
63 | font-style: italic;
64 | font-weight: 700;
65 | src: url('fpTVHK8qsXbIeTHTrnQH6PgYMAt3u4NmhhzLLLPJ5qH3rGVtsTkPsbDajuO5ueQw.woff') format('woff');
66 | }
67 | @font-face {
68 | font-family: 'Source Sans Pro';
69 | font-style: italic;
70 | font-weight: 900;
71 | src: url('fpTVHK8qsXbIeTHTrnQH6MJvEBP8Mx4XcuTrPnlPwTr3rGVtsTkPsbDajuO5ueQw.woff') format('woff');
72 | }
--------------------------------------------------------------------------------
/gui/assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGC-IiwWNzQT_LXAtr-Ee9Pw.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGC-IiwWNzQT_LXAtr-Ee9Pw.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGC7eGk4PJkA83J1AXCmgUfc.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGC7eGk4PJkA83J1AXCmgUfc.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGCmgpmuQqK2I-L2S9cF65Ek.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGCmgpmuQqK2I-L2S9cF65Ek.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGIqjGYJUyOXcBwUQbRaNH6c.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGIqjGYJUyOXcBwUQbRaNH6c.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGMVNtom4QlEDNJaqqqzqdSs.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGMVNtom4QlEDNJaqqqzqdSs.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/gui/assets/fonts/fonts.css:
--------------------------------------------------------------------------------
1 | /*@font-face {
2 | font-family: 'Source Sans Pro';
3 | font-style: normal;
4 | font-weight: 200;
5 | src: local('Source Sans Pro ExtraLight'), local('SourceSansPro-ExtraLight'), url('assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGC-IiwWNzQT_LXAtr-Ee9Pw.woff') format('woff');
6 | }
7 | @font-face {
8 | font-family: 'Source Sans Pro';
9 | font-style: normal;
10 | font-weight: 300;
11 | src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGMVNtom4QlEDNJaqqqzqdSs.woff') format('woff');
12 | }*/
13 | @font-face {
14 | font-family: 'Source Sans Pro';
15 | font-style: normal;
16 | font-weight: 400;
17 | src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url('assets/fonts/Source Sans Pro/ODelI1aHBYDBqgeIAH2zlNHq-FFgoDNV3GTKpHwuvtI.woff') format('woff');
18 | }
19 | /*@font-face {
20 | font-family: 'Source Sans Pro';
21 | font-style: normal;
22 | font-weight: 600;
23 | src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), url('assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGCmgpmuQqK2I-L2S9cF65Ek.woff') format('woff');
24 | }*/
25 | @font-face {
26 | font-family: 'Source Sans Pro';
27 | font-style: normal;
28 | font-weight: 700;
29 | src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url('assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGIqjGYJUyOXcBwUQbRaNH6c.woff') format('woff');
30 | }
31 | @font-face {
32 | font-family: 'Source Sans Pro';
33 | font-style: normal;
34 | font-weight: 900;
35 | src: local('Source Sans Pro Black'), local('SourceSansPro-Black'), url('assets/fonts/Source Sans Pro/toadOcfmlt9b38dHJxOBGC7eGk4PJkA83J1AXCmgUfc.woff') format('woff');
36 | }
37 | /*@font-face {
38 | font-family: 'Source Sans Pro';
39 | font-style: italic;
40 | font-weight: 200;
41 | src: local('Source Sans Pro ExtraLight Italic'), local('SourceSansPro-ExtraLightIt'), url('assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6OE3EfhCMemg4BxrY2mmJD_3rGVtsTkPsbDajuO5ueQw.woff') format('woff');
42 | }
43 | @font-face {
44 | font-family: 'Source Sans Pro';
45 | font-style: italic;
46 | font-weight: 300;
47 | src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightIt'), url('assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6H7XMO6S-yJpg1torQFmnv33rGVtsTkPsbDajuO5ueQw.woff') format('woff');
48 | }*/
49 | @font-face {
50 | font-family: 'Source Sans Pro';
51 | font-style: italic;
52 | font-weight: 400;
53 | src: local('Source Sans Pro Italic'), local('SourceSansPro-It'), url('assets/fonts/Source Sans Pro/M2Jd71oPJhLKp0zdtTvoM_bce-VcyLJMRR1FC9qWbU8.woff') format('woff');
54 | }
55 | /*@font-face {
56 | font-family: 'Source Sans Pro';
57 | font-style: italic;
58 | font-weight: 600;
59 | src: local('Source Sans Pro Semibold Italic'), local('SourceSansPro-SemiboldIt'), url('assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6J4LxuTxC3JbLqy8IUt0K1T3rGVtsTkPsbDajuO5ueQw.woff') format('woff');
60 | }
61 | @font-face {
62 | font-family: 'Source Sans Pro';
63 | font-style: italic;
64 | font-weight: 700;
65 | src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldIt'), url('assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6PgYMAt3u4NmhhzLLLPJ5qH3rGVtsTkPsbDajuO5ueQw.woff') format('woff');
66 | }
67 | @font-face {
68 | font-family: 'Source Sans Pro';
69 | font-style: italic;
70 | font-weight: 900;
71 | src: local('Source Sans Pro Black Italic'), local('SourceSansPro-BlackIt'), url('assets/fonts/Source Sans Pro/fpTVHK8qsXbIeTHTrnQH6MJvEBP8Mx4XcuTrPnlPwTr3rGVtsTkPsbDajuO5ueQw.woff') format('woff');
72 | }*/
73 |
74 |
75 |
76 | @font-face {
77 | font-family: 'Montserrat';
78 | font-style: normal;
79 | font-weight: 400;
80 | src: local('Montserrat-Regular'), url('zhcz-_WihjSQC0oHJ9TCYL3hpw3pgy2gAi-Ip7WPMi0.woff') format('woff');
81 | }
82 | @font-face {
83 | font-family: 'Montserrat';
84 | font-style: normal;
85 | font-weight: 700;
86 | src: local('Montserrat-Bold'), url('IQHow_FEYlDC4Gzy_m8fcnbFhgvWbfSbdVg11QabG8w.woff') format('woff');
87 | }
88 |
--------------------------------------------------------------------------------
/gui/assets/images/circle_down.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
--------------------------------------------------------------------------------
/gui/assets/images/circle_ok.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
--------------------------------------------------------------------------------
/gui/assets/images/cloud_fail.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
36 |
--------------------------------------------------------------------------------
/gui/assets/images/cloud_ok.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
34 |
--------------------------------------------------------------------------------
/gui/assets/images/cog.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
24 |
--------------------------------------------------------------------------------
/gui/assets/images/package.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/images/package.png
--------------------------------------------------------------------------------
/gui/assets/images/packal-man.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/images/packal-man.jpg
--------------------------------------------------------------------------------
/gui/assets/images/paypal.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/images/paypal.gif
--------------------------------------------------------------------------------
/gui/assets/images/preloader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/gui/assets/images/preloader.gif
--------------------------------------------------------------------------------
/gui/assets/images/refresh.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
--------------------------------------------------------------------------------
/gui/assets/images/settings.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
--------------------------------------------------------------------------------
/gui/assets/images/user-no.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
24 |
--------------------------------------------------------------------------------
/gui/assets/images/user-yes.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
25 |
--------------------------------------------------------------------------------
/gui/assets/images/warning.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
--------------------------------------------------------------------------------
/gui/assets/js/borderMenu.js:
--------------------------------------------------------------------------------
1 | /**
2 | * borderMenu.js v1.0.0
3 | * http://www.codrops.com
4 | *
5 | * Licensed under the MIT license.
6 | * http://www.opensource.org/licenses/mit-license.php
7 | *
8 | * Copyright 2013, Codrops
9 | * http://www.codrops.com
10 | */
11 | (function() {
12 |
13 | function init() {
14 |
15 | var menu = document.getElementById( 'bt-menu' ),
16 | trigger = menu.querySelector( 'a.bt-menu-trigger' ),
17 | eventtype = 'click',
18 | resetMenu = function() {
19 | classie.remove( menu, 'bt-menu-open' );
20 | classie.add( menu, 'bt-menu-close' );
21 | },
22 | closeClickFn = function( ev ) {
23 | resetMenu();
24 | overlay.removeEventListener( eventtype, closeClickFn );
25 | };
26 |
27 | var overlay = document.createElement('div');
28 | overlay.className = 'bt-overlay';
29 | menu.appendChild( overlay );
30 |
31 | trigger.addEventListener( eventtype, function( ev ) {
32 | ev.stopPropagation();
33 | ev.preventDefault();
34 |
35 | if( classie.has( menu, 'bt-menu-open' ) ) {
36 | resetMenu();
37 | }
38 | else {
39 | classie.remove( menu, 'bt-menu-close' );
40 | classie.add( menu, 'bt-menu-open' );
41 | overlay.addEventListener( eventtype, closeClickFn );
42 | }
43 | });
44 |
45 | }
46 |
47 | init();
48 |
49 | })();
50 |
--------------------------------------------------------------------------------
/gui/assets/js/classie.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * classie - class helper functions
3 | * from bonzo https://github.com/ded/bonzo
4 | *
5 | * classie.has( elem, 'my-class' ) -> true/false
6 | * classie.add( elem, 'my-new-class' )
7 | * classie.remove( elem, 'my-unwanted-class' )
8 | * classie.toggle( elem, 'my-class' )
9 | */
10 |
11 | /*jshint browser: true, strict: true, undef: true */
12 | /*global define: false */
13 |
14 | ( function( window ) {
15 |
16 | 'use strict';
17 |
18 | // class helper functions from bonzo https://github.com/ded/bonzo
19 |
20 | function classReg( className ) {
21 | return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
22 | }
23 |
24 | // classList support for class management
25 | // altho to be fair, the api sucks because it won't accept multiple classes at once
26 | var hasClass, addClass, removeClass;
27 |
28 | if ( 'classList' in document.documentElement ) {
29 | hasClass = function( elem, c ) {
30 | return elem.classList.contains( c );
31 | };
32 | addClass = function( elem, c ) {
33 | elem.classList.add( c );
34 | };
35 | removeClass = function( elem, c ) {
36 | elem.classList.remove( c );
37 | };
38 | }
39 | else {
40 | hasClass = function( elem, c ) {
41 | return classReg( c ).test( elem.className );
42 | };
43 | addClass = function( elem, c ) {
44 | if ( !hasClass( elem, c ) ) {
45 | elem.className = elem.className + ' ' + c;
46 | }
47 | };
48 | removeClass = function( elem, c ) {
49 | elem.className = elem.className.replace( classReg( c ), ' ' );
50 | };
51 | }
52 |
53 | function toggleClass( elem, c ) {
54 | var fn = hasClass( elem, c ) ? removeClass : addClass;
55 | fn( elem, c );
56 | }
57 |
58 | var classie = {
59 | // full names
60 | hasClass: hasClass,
61 | addClass: addClass,
62 | removeClass: removeClass,
63 | toggleClass: toggleClass,
64 | // short names
65 | has: hasClass,
66 | add: addClass,
67 | remove: removeClass,
68 | toggle: toggleClass
69 | };
70 |
71 | // transport
72 | if ( typeof define === 'function' && define.amd ) {
73 | // AMD
74 | define( classie );
75 | } else {
76 | // browser global
77 | window.classie = classie;
78 | }
79 |
80 | })( window );
81 |
--------------------------------------------------------------------------------
/gui/assets/js/keep-alive.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Set a variable and invoke the keepAlive function and execute every 20 seconds
4 | * @param {function} keepAlive() call to function
5 | * @param {int} 20000 try every 20 seconds
6 | * @return {void} returns nothing, just runs every 20 seconds
7 | */
8 | var keepMeAlive=setInterval( function() { keepAlive() }, 20000 );
9 |
10 | /**
11 | * A callback to a keep alive script that updates a file to let a bash script know
12 | * not to kill the webserver
13 | * @return {void} no return value
14 | */
15 | function keepAlive() {
16 | xmlhttp=new XMLHttpRequest();
17 | xmlhttp.open( "GET","http://localhost:7893/webserver-keep-alive-update.php" );
18 | xmlhttp.send();
19 | console.log( "Calling home.");
20 | }
21 |
--------------------------------------------------------------------------------
/gui/index.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Packal Updater
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
29 |
30 |
31 |
Loading...
32 |

33 |
34 |
35 |
Updating...

36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
115 |
116 |
--------------------------------------------------------------------------------
/gui/serve_image.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gui/webserver-keep-alive-update.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/icon.png
--------------------------------------------------------------------------------
/info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | bundleid
6 | com.packal
7 | category
8 | Tools
9 | connections
10 |
11 | 1F4D4C11-58BD-413E-9E17-D93F880D403C
12 |
13 |
14 | destinationuid
15 | C1FFB920-0CA6-4611-ACCE-9D08E0295195
16 | modifiers
17 | 0
18 | modifiersubtext
19 |
20 |
21 |
22 | 2BF4F0C5-F584-44E2-9216-78FF884C965C
23 |
24 |
25 | destinationuid
26 | DC36F13D-1A70-4093-948E-569723637CD2
27 | modifiers
28 | 0
29 | modifiersubtext
30 |
31 |
32 |
33 | 47D96588-97DE-4BD3-BCD4-E23FC751B881
34 |
35 |
36 | destinationuid
37 | 75EA4D1A-6D61-4028-8023-81F9AFFEA680
38 | modifiers
39 | 0
40 | modifiersubtext
41 |
42 |
43 |
44 | 75EA4D1A-6D61-4028-8023-81F9AFFEA680
45 |
46 |
47 | destinationuid
48 | F3825148-0DEF-4920-8AA9-2675D7B90496
49 | modifiers
50 | 0
51 | modifiersubtext
52 |
53 |
54 |
55 | 7955C2E8-A67A-423F-AF99-078BB269996F
56 |
57 |
58 | destinationuid
59 | 47D96588-97DE-4BD3-BCD4-E23FC751B881
60 | modifiers
61 | 0
62 | modifiersubtext
63 |
64 |
65 |
66 | BD4CD001-D2F2-4403-ADAE-991B88EF9C43
67 |
68 |
69 | destinationuid
70 | F3825148-0DEF-4920-8AA9-2675D7B90496
71 | modifiers
72 | 0
73 | modifiersubtext
74 |
75 |
76 |
77 | C1FFB920-0CA6-4611-ACCE-9D08E0295195
78 |
79 |
80 | destinationuid
81 | BD4CD001-D2F2-4403-ADAE-991B88EF9C43
82 | modifiers
83 | 0
84 | modifiersubtext
85 |
86 |
87 |
88 | DC36F13D-1A70-4093-948E-569723637CD2
89 |
90 |
91 | destinationuid
92 | EEB94641-1F4D-4E1C-82DD-69E4E582A9E4
93 | modifiers
94 | 0
95 | modifiersubtext
96 |
97 |
98 |
99 |
100 | createdby
101 | Shawn Patrick Rice
102 | description
103 | A package manager for Alfred
104 | disabled
105 |
106 | name
107 | Packal Updater
108 | objects
109 |
110 |
111 | config
112 |
113 | concurrently
114 |
115 | escaping
116 | 127
117 | script
118 | php packal-controller-script.php "{query}"
119 | type
120 | 0
121 |
122 | type
123 | alfred.workflow.action.script
124 | uid
125 | 75EA4D1A-6D61-4028-8023-81F9AFFEA680
126 | version
127 | 0
128 |
129 |
130 | config
131 |
132 | triggerid
133 | com.packal.start
134 |
135 | type
136 | alfred.workflow.trigger.external
137 | uid
138 | 1F4D4C11-58BD-413E-9E17-D93F880D403C
139 | version
140 | 0
141 |
142 |
143 | config
144 |
145 | argumenttype
146 | 1
147 | escaping
148 | 127
149 | keyword
150 | packal
151 | queuedelaycustom
152 | 1
153 | queuedelayimmediatelyinitially
154 |
155 | queuedelaymode
156 | 0
157 | queuemode
158 | 1
159 | runningsubtext
160 | Talking to server and processing data...
161 | script
162 | php script.php "{query}"
163 | title
164 | Update your packages
165 | type
166 | 0
167 | withspace
168 |
169 |
170 | type
171 | alfred.workflow.input.scriptfilter
172 | uid
173 | C1FFB920-0CA6-4611-ACCE-9D08E0295195
174 | version
175 | 0
176 |
177 |
178 | config
179 |
180 | concurrently
181 |
182 | escaping
183 | 127
184 | script
185 | php packal-controller-script.php "{query}"
186 | type
187 | 0
188 |
189 | type
190 | alfred.workflow.action.script
191 | uid
192 | BD4CD001-D2F2-4403-ADAE-991B88EF9C43
193 | version
194 | 0
195 |
196 |
197 | config
198 |
199 | argumenttype
200 | 0
201 | escaping
202 | 127
203 | queuedelaycustom
204 | 1
205 | queuedelayimmediatelyinitially
206 |
207 | queuedelaymode
208 | 0
209 | queuemode
210 | 1
211 | script
212 | php script-set-option.php "{query}"
213 | title
214 | Set option
215 | type
216 | 0
217 | withspace
218 |
219 |
220 | type
221 | alfred.workflow.input.scriptfilter
222 | uid
223 | 47D96588-97DE-4BD3-BCD4-E23FC751B881
224 | version
225 | 0
226 |
227 |
228 | config
229 |
230 | triggerid
231 | set-option
232 |
233 | type
234 | alfred.workflow.trigger.external
235 | uid
236 | 7955C2E8-A67A-423F-AF99-078BB269996F
237 | version
238 | 0
239 |
240 |
241 | config
242 |
243 | lastpathcomponent
244 |
245 | onlyshowifquerypopulated
246 |
247 | output
248 | 2
249 | removeextension
250 |
251 | sticky
252 |
253 | text
254 | {query}
255 | title
256 | Packal
257 |
258 | type
259 | alfred.workflow.output.notification
260 | uid
261 | F3825148-0DEF-4920-8AA9-2675D7B90496
262 | version
263 | 0
264 |
265 |
266 | config
267 |
268 | concurrently
269 |
270 | escaping
271 | 102
272 | script
273 | env
274 | type
275 | 0
276 |
277 | type
278 | alfred.workflow.action.script
279 | uid
280 | DC36F13D-1A70-4093-948E-569723637CD2
281 | version
282 | 0
283 |
284 |
285 | config
286 |
287 | argumenttype
288 | 2
289 | keyword
290 | packal
291 | text
292 | Packal Info
293 | withspace
294 |
295 |
296 | type
297 | alfred.workflow.input.keyword
298 | uid
299 | 2BF4F0C5-F584-44E2-9216-78FF884C965C
300 | version
301 | 0
302 |
303 |
304 | config
305 |
306 | autopaste
307 |
308 | clipboardtext
309 | {query}
310 |
311 | type
312 | alfred.workflow.output.clipboard
313 | uid
314 | EEB94641-1F4D-4E1C-82DD-69E4E582A9E4
315 | version
316 | 0
317 |
318 |
319 | readme
320 | See https://github.com/shawnrice/packal
321 | Or http://www.packal.org
322 | uidata
323 |
324 | 1F4D4C11-58BD-413E-9E17-D93F880D403C
325 |
326 | ypos
327 | 130
328 |
329 | 2BF4F0C5-F584-44E2-9216-78FF884C965C
330 |
331 | ypos
332 | 430
333 |
334 | 47D96588-97DE-4BD3-BCD4-E23FC751B881
335 |
336 | ypos
337 | 310
338 |
339 | 75EA4D1A-6D61-4028-8023-81F9AFFEA680
340 |
341 | ypos
342 | 10
343 |
344 | 7955C2E8-A67A-423F-AF99-078BB269996F
345 |
346 | ypos
347 | 310
348 |
349 | BD4CD001-D2F2-4403-ADAE-991B88EF9C43
350 |
351 | ypos
352 | 250
353 |
354 | C1FFB920-0CA6-4611-ACCE-9D08E0295195
355 |
356 | ypos
357 | 130
358 |
359 | DC36F13D-1A70-4093-948E-569723637CD2
360 |
361 | ypos
362 | 420
363 |
364 | EEB94641-1F4D-4E1C-82DD-69E4E582A9E4
365 |
366 | ypos
367 | 450
368 |
369 | F3825148-0DEF-4920-8AA9-2675D7B90496
370 |
371 | ypos
372 | 330
373 |
374 |
375 | webaddress
376 | http://www.packal.org
377 |
378 |
379 |
--------------------------------------------------------------------------------
/init.php:
--------------------------------------------------------------------------------
1 | $alfred_version,
30 | 'cache_dir' => $cache_dir,
31 | 'data_dir' => $data_dir,
32 | 'workflows_dir' => $workflows_dir,
33 | 'alfred_preferences' => $_SERVER['alfred_preferences'],
34 | 'HOME' => $_SERVER['HOME'],
35 | ];
36 | if ( ! file_exists( '/tmp/com.packal' ) ) {
37 | mkdir( '/tmp/com.packal' );
38 | }
39 | file_put_contents( '/tmp/com.packal/config.json', json_encode( $operation_data ) );
40 | define( 'ALFRED_VERSION', 'Alfred ' . guess_alfred_version() );
41 | define( 'CACHE_DIR', __CACHE__ );
42 | define( 'DATA_DIR', __DATA__ );
43 | define( 'WORKFLOWS_DIR', $workflows_dir );
44 | } else {
45 | // we're now somewhere else and need this data because it doesn't appear
46 | if ( file_exists( '/tmp/com.packal' ) ) {
47 | $operation_data = json_decode( file_get_contents( '/tmp/com.packal/config.json' ), true );
48 | define( 'ALFRED_VERSION', $operation_data['alfred_version'] );
49 | define( 'CACHE_DIR', $operation_data['cache_dir'] );
50 | define( 'DATA_DIR', $operation_data['data_dir'] );
51 | define( 'WORKFLOWS_DIR', $operation_data['workflows_dir'] );
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/install-alfred-cron-script.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This installs the check updates script into Alfred Cron
4 | # alfred.cron.spr
5 |
6 | bundle="alfred.cron.spr"
7 |
8 | data="$HOME/Library/Application Support/Alfred 2/Workflow Data/$bundle"
9 | cache="$HOME/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/$bundle"
10 | scriptDir="$data/scripts"
11 | enabledScriptDir="$data/scripts/enabled"
12 |
13 | name='packal_updater'
14 |
15 | head='#!/bin/bash\nset -o errexit'
16 | interval='86400'
17 |
18 | dir=`cat "$HOME/Library/Application Support/Alfred 2/Workflow Data/com.packal/endpoints/endpoints.list"|grep '"com.packal"='`
19 | dir=`echo "$dir"|tr '"' ' '`
20 | dir=`echo ${dir# com.packal = }`
21 | command="#!/bin/bash
22 | set -o errexit
23 |
24 | php '$dir/assets/alfred.cron.script.php'"
25 |
26 | if [[ ! "$command" =~ "#!/bin/bash" ]]; then
27 | command=`echo "#!/bin/bash\nset -o errexit\n$command"`
28 | fi
29 | echo "$command" > "$scriptDir/$name"
30 |
31 | # Delete an job if the name is already in there. This error should already
32 | # have been accounted for.
33 | awk '!/'"$name"'/' "$data/registry" > "$cache/registry" && mv "$cache/registry" "$data/registry"
34 | echo "$name"="$interval" >> "$data/registry"
35 |
36 | # Enable the script
37 | ln "$scriptDir/$name" "$enabledScriptDir/$name"
--------------------------------------------------------------------------------
/libraries/workflows.php:
--------------------------------------------------------------------------------
1 | path = exec('pwd');
34 | $this->home = exec('printf "$HOME"');
35 |
36 | if ( file_exists( 'info.plist' ) ):
37 | $this->bundle = $this->get( 'bundleid', 'info.plist' );
38 | endif;
39 |
40 | if ( !is_null( $bundleid ) ):
41 | $this->bundle = $bundleid;
42 | endif;
43 |
44 | $this->cache = CACHE_DIR;
45 | $this->data = DATA_DIR;
46 |
47 | if ( !file_exists( $this->cache ) ):
48 | exec("mkdir '".$this->cache."'");
49 | endif;
50 |
51 | if ( !file_exists( $this->data ) ):
52 | exec("mkdir '".$this->data."'");
53 | endif;
54 |
55 | $this->results = array();
56 | }
57 |
58 | /**
59 | * Description:
60 | * Accepts no parameter and returns the value of the bundle id for the current workflow.
61 | * If no value is available, then false is returned.
62 | *
63 | * @param none
64 | * @return false if not available, bundle id value if available.
65 | */
66 | public function bundle()
67 | {
68 | if ( is_null( $this->bundle ) ):
69 | return false;
70 | else:
71 | return $this->bundle;
72 | endif;
73 | }
74 |
75 | /**
76 | * Description:
77 | * Accepts no parameter and returns the value of the path to the cache directory for your
78 | * workflow if it is available. Returns false if the value isn't available.
79 | *
80 | * @param none
81 | * @return false if not available, path to the cache directory for your workflow if available.
82 | */
83 | public function cache()
84 | {
85 | if ( is_null( $this->bundle ) ):
86 | return false;
87 | else:
88 | if ( is_null( $this->cache ) ):
89 | return false;
90 | else:
91 | return $this->cache;
92 | endif;
93 | endif;
94 | }
95 |
96 | /**
97 | * Description:
98 | * Accepts no parameter and returns the value of the path to the storage directory for your
99 | * workflow if it is available. Returns false if the value isn't available.
100 | *
101 | * @param none
102 | * @return false if not available, path to the storage directory for your workflow if available.
103 | */
104 | public function data()
105 | {
106 | if ( is_null( $this->bundle ) ):
107 | return false;
108 | else:
109 | if ( is_null( $this->data ) ):
110 | return false;
111 | else:
112 | return $this->data;
113 | endif;
114 | endif;
115 | }
116 |
117 | /**
118 | * Description:
119 | * Accepts no parameter and returns the value of the path to the current directory for your
120 | * workflow if it is available. Returns false if the value isn't available.
121 | *
122 | * @param none
123 | * @return false if not available, path to the current directory for your workflow if available.
124 | */
125 | public function path()
126 | {
127 | if ( is_null( $this->path ) ):
128 | return false;
129 | else:
130 | return $this->path;
131 | endif;
132 | }
133 |
134 | /**
135 | * Description:
136 | * Accepts no parameter and returns the value of the home path for the current user
137 | * Returns false if the value isn't available.
138 | *
139 | * @param none
140 | * @return false if not available, home path for the current user if available.
141 | */
142 | public function home()
143 | {
144 | if ( is_null( $this->home ) ):
145 | return false;
146 | else:
147 | return $this->home;
148 | endif;
149 | }
150 |
151 | /**
152 | * Description:
153 | * Returns an array of available result items
154 | *
155 | * @param none
156 | * @return array - list of result items
157 | */
158 | public function results()
159 | {
160 | return $this->results;
161 | }
162 |
163 | /**
164 | * Description:
165 | * Convert an associative array into XML format
166 | *
167 | * @param $a - An associative array to convert
168 | * @param $format - format of data being passed (json or array), defaults to array
169 | * @return - XML string representation of the array
170 | */
171 | public function toxml( $a=null, $format='array' ) {
172 |
173 | if ( $format == 'json' ):
174 | $a = json_decode( $a, TRUE );
175 | endif;
176 |
177 | if ( is_null( $a ) && !empty( $this->results ) ):
178 | $a = $this->results;
179 | elseif ( is_null( $a ) && empty( $this->results ) ):
180 | return false;
181 | endif;
182 |
183 | $items = new SimpleXMLElement(""); // Create new XML element
184 |
185 | foreach( $a as $b ): // Lop through each object in the array
186 | $c = $items->addChild( 'item' ); // Add a new 'item' element for each object
187 | $c_keys = array_keys( $b ); // Grab all the keys for that item
188 | foreach( $c_keys as $key ): // For each of those keys
189 | if ( $key == 'uid' ):
190 | if ( $b[$key] === null || $b[$key] === '' ):
191 | continue;
192 | else:
193 | $c->addAttribute( 'uid', $b[$key] );
194 | endif;
195 | elseif ( $key == 'arg' ):
196 | $c->addAttribute( 'arg', $b[$key] );
197 | $c->$key = $b[$key];
198 | elseif ( $key == 'type' ):
199 | $c->addAttribute( 'type', $b[$key] );
200 | elseif ( $key == 'valid' ):
201 | if ( $b[$key] == 'yes' || $b[$key] == 'no' ):
202 | $c->addAttribute( 'valid', $b[$key] );
203 | endif;
204 | elseif ( $key == 'autocomplete' ):
205 | if ( $b[$key] === null || $b[$key] === '' ):
206 | continue;
207 | else:
208 | $c->addAttribute( 'autocomplete', $b[$key] );
209 | endif;
210 | elseif ( $key == 'icon' ):
211 | if ( substr( $b[$key], 0, 9 ) == 'fileicon:' ):
212 | $val = substr( $b[$key], 9 );
213 | $c->$key = $val;
214 | $c->$key->addAttribute( 'type', 'fileicon' );
215 | elseif ( substr( $b[$key], 0, 9 ) == 'filetype:' ):
216 | $val = substr( $b[$key], 9 );
217 | $c->$key = $val;
218 | $c->$key->addAttribute( 'type', 'filetype' );
219 | else:
220 | $c->$key = $b[$key];
221 | endif;
222 | else:
223 | $c->$key = $b[$key];
224 | endif;
225 | endforeach;
226 | endforeach;
227 |
228 | return $items->asXML(); // Return XML string representation of the array
229 |
230 | }
231 |
232 | /**
233 | * Description:
234 | * Remove all items from an associative array that do not have a value
235 | *
236 | * @param $a - Associative array
237 | * @return bool
238 | */
239 | private function empty_filter( $a ) {
240 | if ( $a == '' || $a == null ): // if $a is empty or null
241 | return false; // return false, else, return true
242 | else:
243 | return true;
244 | endif;
245 | }
246 |
247 | /**
248 | * Description:
249 | * Save values to a specified plist. If the first parameter is an associative
250 | * array, then the second parameter becomes the plist file to save to. If the
251 | * first parameter is string, then it is assumed that the first parameter is
252 | * the label, the second parameter is the value, and the third parameter is
253 | * the plist file to save the data to.
254 | *
255 | * @param $a - associative array of values to save
256 | * @param $b - the value of the setting
257 | * @param $c - the plist to save the values into
258 | * @return string - execution output
259 | */
260 | public function set( $a=null, $b=null, $c=null )
261 | {
262 | if ( is_array( $a ) ):
263 | if ( file_exists( $b ) ):
264 | if ( file_exists( $this->path.'/'.$b ) ):
265 | $b = $this->path.'/'.$b;
266 | endif;
267 | elseif ( file_exists( $this->data."/".$b ) ):
268 | $b = $this->data."/".$b;
269 | elseif ( file_exists( $this->cache."/".$b ) ):
270 | $b = $this->cache."/".$b;
271 | else:
272 | $b = $this->data."/".$b;
273 | endif;
274 | else:
275 | if ( file_exists( $c ) ):
276 | if ( file_exists( $this->path.'/'.$c ) ):
277 | $c = $this->path.'/'.$c;
278 | endif;
279 | elseif ( file_exists( $this->data."/".$c ) ):
280 | $c = $this->data."/".$c;
281 | elseif ( file_exists( $this->cache."/".$c ) ):
282 | $c = $this->cache."/".$c;
283 | else:
284 | $c = $this->data."/".$c;
285 | endif;
286 | endif;
287 |
288 | if ( is_array( $a ) ):
289 | foreach( $a as $k => $v ):
290 | exec( 'defaults write "'. $b .'" '. $k .' "'. $v .'"');
291 | endforeach;
292 | else:
293 | exec( 'defaults write "'. $c .'" '. $a .' "'. $b .'"');
294 | endif;
295 | }
296 |
297 | /**
298 | * Description:
299 | * Read a value from the specified plist
300 | *
301 | * @param $a - the value to read
302 | * @param $b - plist to read the values from
303 | * @return bool false if not found, string if found
304 | */
305 | public function get( $a, $b ) {
306 |
307 | if ( file_exists( $b ) ):
308 | if ( file_exists( $this->path.'/'.$b ) ):
309 | $b = $this->path.'/'.$b;
310 | endif;
311 | elseif ( file_exists( $this->data."/".$b ) ):
312 | $b = $this->data."/".$b;
313 | elseif ( file_exists( $this->cache."/".$b ) ):
314 | $b = $this->cache."/".$b;
315 | else:
316 | return false;
317 | endif;
318 |
319 | exec( 'defaults read "'. $b .'" '.$a, $out ); // Execute system call to read plist value
320 |
321 | if ( $out == "" ):
322 | return false;
323 | endif;
324 |
325 | $out = $out[0];
326 | return $out; // Return item value
327 | }
328 |
329 | /**
330 | * Description:
331 | * Read data from a remote file/url, essentially a shortcut for curl
332 | *
333 | * @param $url - URL to request
334 | * @param $options - Array of curl options
335 | * @return result from curl_exec
336 | */
337 | public function request( $url=null, $options=null )
338 | {
339 | if ( is_null( $url ) ):
340 | return false;
341 | endif;
342 |
343 | $defaults = array( // Create a list of default curl options
344 | CURLOPT_RETURNTRANSFER => true, // Returns the result as a string
345 | CURLOPT_URL => $url, // Sets the url to request
346 | CURLOPT_FRESH_CONNECT => true
347 | );
348 |
349 | if ( $options ):
350 | foreach( $options as $k => $v ):
351 | $defaults[$k] = $v;
352 | endforeach;
353 | endif;
354 |
355 | array_filter( $defaults, // Filter out empty options from the array
356 | array( $this, 'empty_filter' ) );
357 |
358 | $ch = curl_init(); // Init new curl object
359 | curl_setopt_array( $ch, $defaults ); // Set curl options
360 | $out = curl_exec( $ch ); // Request remote data
361 | $err = curl_error( $ch );
362 | curl_close( $ch ); // End curl request
363 |
364 | if ( $err ):
365 | return $err;
366 | else:
367 | return $out;
368 | endif;
369 | }
370 |
371 | /**
372 | * Description:
373 | * Allows searching the local hard drive using mdfind
374 | *
375 | * @param $query - search string
376 | * @return array - array of search results
377 | */
378 | public function mdfind( $query )
379 | {
380 | exec('mdfind "'.$query.'"', $results);
381 | return $results;
382 | }
383 |
384 | /**
385 | * Description:
386 | * Accepts data and a string file name to store data to local file as cache
387 | *
388 | * @param array - data to save to file
389 | * @param file - filename to write the cache data to
390 | * @return none
391 | */
392 | public function write( $a, $b )
393 | {
394 | if ( file_exists( $b ) ):
395 | if ( file_exists( $this->path.'/'.$b ) ):
396 | $b = $this->path.'/'.$b;
397 | endif;
398 | elseif ( file_exists( $this->data."/".$b ) ):
399 | $b = $this->data."/".$b;
400 | elseif ( file_exists( $this->cache."/".$b ) ):
401 | $b = $this->cache."/".$b;
402 | else:
403 | $b = $this->data."/".$b;
404 | endif;
405 |
406 | if ( is_array( $a ) ):
407 | $a = json_encode( $a );
408 | file_put_contents( $b, $a );
409 | return true;
410 | elseif ( is_string( $a ) ):
411 | file_put_contents( $b, $a );
412 | return true;
413 | else:
414 | return false;
415 | endif;
416 | }
417 |
418 | /**
419 | * Description:
420 | * Returns data from a local cache file
421 | *
422 | * @param file - filename to read the cache data from
423 | * @return false if the file cannot be found, the file data if found. If the file
424 | * format is json encoded, then a json object is returned.
425 | */
426 | public function read( $a, $array = false )
427 | {
428 | if ( file_exists( $a ) ):
429 | if ( file_exists( $this->path.'/'.$a ) ):
430 | $a = $this->path.'/'.$a;
431 | endif;
432 | elseif ( file_exists( $this->data."/".$a ) ):
433 | $a = $this->data."/".$a;
434 | elseif ( file_exists( $this->cache."/".$a ) ):
435 | $a = $this->cache."/".$a;
436 | else:
437 | return false;
438 | endif;
439 |
440 | $out = file_get_contents( $a );
441 | if ( !is_null( json_decode( $out ) ) && !$array ):
442 | $out = json_decode( $out );
443 | elseif ( !is_null( json_decode( $out ) ) && !$array ):
444 | $out = json_decode( $out, true );
445 | endif;
446 |
447 | return $out;
448 | }
449 |
450 | /**
451 | * Description:
452 | * Helper function that just makes it easier to pass values into a function
453 | * and create an array result to be passed back to Alfred
454 | *
455 | * @param $uid - the uid of the result, should be unique
456 | * @param $arg - the argument that will be passed on
457 | * @param $title - The title of the result item
458 | * @param $sub - The subtitle text for the result item
459 | * @param $icon - the icon to use for the result item
460 | * @param $valid - sets whether the result item can be actioned
461 | * @param $auto - the autocomplete value for the result item
462 | * @return array - array item to be passed back to Alfred
463 | */
464 | public function result( $uid, $arg, $title, $sub, $icon, $valid='yes', $auto=null, $type=null )
465 | {
466 | $temp = array(
467 | 'uid' => $uid,
468 | 'arg' => $arg,
469 | 'title' => $title,
470 | 'subtitle' => $sub,
471 | 'icon' => $icon,
472 | 'valid' => $valid,
473 | 'autocomplete' => $auto,
474 | 'type' => $type
475 | );
476 |
477 | if ( is_null( $type ) ):
478 | unset( $temp['type'] );
479 | endif;
480 |
481 | array_push( $this->results, $temp );
482 |
483 | return $temp;
484 | }
485 |
486 | }
--------------------------------------------------------------------------------
/notes.txt:
--------------------------------------------------------------------------------
1 | Note to self and anyone else who happens to read this:
2 |
3 | The code here is a bit messy and uncommented. Some of it is hacky. Some extra images are included, but those are for possible future use. They're small.
4 |
5 | @TODO: Comment Code
6 | @TODO: Rewrite as class to reuse code and limit outgoing calls to bare minimum
7 | @TODO: Finish non-essential CLI functionality
8 | @TODO: Clean up CLI scripts
9 | @TODO: Re-implement 'Notification Options'
10 | @TODO: Re-implement 'Force Packal' option
11 | @TODO: Create viable webserver that works Pre-Mavericks
12 | @TODO: Reorganize paths and prune extra files
13 | @TODO: Better error handling (fail more gracefully)
14 | @TODO: Make sorting better in workflow
15 | @TODO: Implement workflow reporting more elegantly
16 | @TODO: Re-implement API key functionality
17 | @TODO: Create Push-to-Packal functionality
18 | @TODO: Add in more extenal triggers for better manipulation of workflow
19 | @TODO: Refine language used throughout GUI and workflow
20 | @TODO: Reorganize for better lazy-loading of longer calls
21 | @TODO: Implement Alphred library
22 | @TODO: Finish writing Alphred library
23 | @TODO: Get better icons
24 |
25 | @TODO: Fix typo when no Internet connection is available on status page of GUI
26 |
27 |
28 | nohup sleep 10 > /dev/null 2>&1 ; '/Users/Sven/Library/Application Support/Alfred 2/Workflow Data/alfred.bundler-aries/assets/utility/terminal-notifier/default/terminal-notifier.app/Contents/MacOS/terminal-notifier' -message 'packal-updater-settings' > /dev/null 2>&1 &
--------------------------------------------------------------------------------
/packal-controller-script.php:
--------------------------------------------------------------------------------
1 | DATA_DIR, 'cache_dir' => CACHE_DIR, 'alfred_version' => ALFRED_VERSION ];
39 | // if ( ! file_exists( '/tmp/com.packal' ) ) {
40 | // mkdir( '/tmp/com.packal' );
41 | // }
42 | // file_put_contents( '/tmp/com.packal/config.json', json_encode( $operation_data ) );
43 |
44 | // Since we're using Mavericks or greater, we can just use the native php 5.4 binary.
45 | exec( 'nohup php -S localhost:7893 -t gui/ > /dev/null 2>&1 &' );
46 | } else {
47 | // Not using Mavericks, so php 5.3 is installed.
48 | // For now, fuck it. I've tried to come up with too many workarounds.
49 | // No GUI for you.
50 | die();
51 | }
52 |
53 | // Start the webserver kill script
54 | exec( "nohup '$dir/check-and-kill-webserver.sh' > /dev/null 2>&1 &" );
55 | exec( "nohup php '$dir/gui/webserver-keep-alive-update.php' > /dev/null 2>&1 &" );
56 |
57 | // Wait a second so that we can make sure that the webserver has started before we open the viewer.
58 | sleep( 2 );
59 |
60 | $viewer = __load( 'viewer', 'default', 'utility' );
61 | // Okay, so if there is an old version of the bundler, then we'll do the correction for this.
62 | if ( strpos( $viewer, '--args' ) ) {
63 | $viewer = substr( $viewer, 0, strlen( $viewer ) - 6 );
64 | }
65 |
66 | // Open the gui in the viewer
67 | exec( "nohup open $viewer --args http://localhost:7893 > /dev/null 2>&1 &" );
68 |
69 | $script = 'tell application "System Events" to set frontmost of process "Application Stub" to true';
70 | exec( "osascript -e '$script'" );
71 |
72 | die();
73 | }
74 |
75 |
76 | if ( strpos( $q, 'update-' ) !== false ) {
77 | $workflows = json_decode( file_get_contents( "$data/endpoints/endpoints.json" ), true );
78 | $wf = array_keys( $workflows );
79 | if ( str_replace( 'update-', '', $q ) == 'all' ) {
80 | $result = exec( 'php cli/packal.php doUpdateAll ' );
81 | } else {
82 | if ( in_array( str_replace( 'update-', '', $q ), $wf ) ) {
83 | $cmd = 'php cli/packal.php doUpdate ' . str_replace( 'update-', '', $q );
84 | $result = exec( $cmd );
85 | if ( $result == 'TRUE' ) {
86 | $plist = $workflows[ str_replace( 'update-', '', $q ) ] . '/info.plist';
87 | $name = exec( "/usr/libexec/PlistBuddy -c \"Print :name\" '$plist' 2> /dev/null" );
88 | // echo $name . " has been successfully updated.";
89 | } else {
90 | $plist = $workflows[ str_replace( 'update-', '', $q ) ] . '/info.plist';
91 | $name = exec( "/usr/libexec/PlistBuddy -c \"Print :name\" '$plist' 2> /dev/null" );
92 | echo 'Error updating ' . $name;
93 | }
94 | }
95 | }
96 | }
97 |
98 | // We haven't possibly needed these yet, so we'll load them here.
99 | $tn = __load( 'terminal-notifier' , 'default' , 'utility' );
100 | $endpoints = json_decode( file_get_contents( "$data/endpoints/endpoints.json" ), true );
101 |
102 |
103 | if ( strpos( $q, 'option-set-' ) !== false ) {
104 | $set = str_replace( 'option-set-', '', $q );
105 | $set = explode( '-', $set );
106 | $set[1] = (string) $set[1];
107 |
108 | if ( count( $set ) > 2 ) {
109 | echo 'Too many hyphens.';
110 | die();
111 | }
112 |
113 | if ( empty( $set[1] ) ) {
114 | $set[1] = 'null';
115 | }
116 |
117 | // Just in case something wasn't quoted correctly.
118 | $set[1] = str_replace( '\ ', ' ', $set[1] );
119 |
120 | if ( ( $set[0] == 'username' ) && ( $set[1] == 'null' ) ) {
121 | $cmd = ( 'php cli/packal.php setOption packalAccount 0' );
122 | exec( $cmd );
123 | $cmd = ( "php cli/packal.php setOption username ''" );
124 | exec( $cmd );
125 | exec( "$tn -title 'Packal Updater' -message 'You no longer have a Packal username set.' -group 'packal-updater-settings'" );
126 |
127 | die();
128 | }
129 | if ( ( $set[0] == 'packalAccount') && ( $set[1] == '1' ) ) {
130 | $cmd = ( 'php cli/packal.php setOption packalAccount 1' );
131 | exec( $cmd );
132 | $script = 'tell application "' . ALFRED_VERSION . '" to run trigger "set-option" in workflow "com.packal" with argument "username:"';
133 | exec( "osascript -e '$script'" );
134 | die();
135 | }
136 |
137 | if ( ( $set[0] == 'packalAccount') && ( $set[1] == '0' ) ) {
138 | $cmd = ( 'php cli/packal.php setOption packalAccount 0' );
139 | exec( $cmd );
140 | $cmd = ( "php cli/packal.php setOption username ''" );
141 | exec( $cmd );
142 | exec( "$tn -title 'Packal Updater' -message 'You no longer have a Packal username set.' -group 'packal-updater-settings'" );
143 | die();
144 | }
145 | if ( ( $set[0] == 'authorName' ) && ( $set[1] == 'null' ) ) {
146 | $cmd = ( "php cli/packal.php setOption authorName ''" );
147 | exec( $cmd );
148 | exec( "$tn -title 'Packal Updater' -message 'You no longer have a author name set.' -group 'packal-updater-settings'" );
149 |
150 | die();
151 | }
152 |
153 | if ( $set[0] == 'workflowReporting' ) {
154 |
155 | // Possible Data Correction
156 | if ( $set[1] == 'null' ) {
157 | $set[1] = 0;
158 | }
159 |
160 | // Set the value
161 | $cmd = 'php cli/packal.php setOption workflowReporting ' . $set[1];
162 | exec( $cmd );
163 |
164 | // Send the notification
165 | if ( $set[1] == 1 ) {
166 | exec( "$tn -title 'Packal Updater' -message 'You will now send anonymous usage data to Packal.org.' -group 'packal-updater-settings'" );
167 | } else { exec( "$tn -title 'Packal Updater' -message 'You will __not__ send anonymous usage data to Packal.org.' -group 'packal-updater-settings'" );
168 | }
169 |
170 | // Die. Die. Die.
171 | die();
172 | }
173 |
174 | $cmd = ( 'php cli/packal.php setOption ' . $set[0] . " '" . $set[1] . "'" );
175 | exec( $cmd );
176 |
177 | switch ( $set[0] ) :
178 | case 'backups' :
179 | $message = 'The updater will now keep ' . $set[1] . ' backups of workflows.';
180 | break;
181 | case 'authorName' :
182 | $message = 'Your author name is now set to ' . $set[1] . '.';
183 | break;
184 | case 'username' :
185 | $message = 'Your Packal.org username is now set to ' . $set[1] . '.';
186 | break;
187 | endswitch;
188 |
189 | if ( isset( $message ) ) {
190 | exec( "$tn -title 'Packal Updater' -message '$message' -group 'packal-updater-settings'" );
191 | }
192 |
193 | // Option to set a custom icon. It doesn't seem to be working right now, so commented out.
194 | // if ( $osx == '10.9' || $osx == '10.10' )
195 | // $tnicon = "-appIcon '" . __DIR__ . "assets/icons/package.png'";
196 |
197 |
198 |
199 |
200 | // @TODO: Add in Terminal Notifier notification.
201 | die();
202 |
203 | }
204 |
205 | if ( strpos( $q, 'set-' ) !== false ) {
206 | $option = str_replace( 'set-', '', $q );
207 | $script = 'tell application "' . ALFRED_VERSION . '" to run trigger "set-option" in workflow "com.packal" with argument "' . $option . ': "';
208 | exec( "osascript -e '$script'" );
209 | die();
210 | }
211 |
212 | if ( strpos( $q, 'blacklist-' ) !== false ) {
213 | $workflow = str_replace( 'blacklist-', '', $q );
214 | $blacklist = json_decode( file_get_contents( "$data/config/blacklist.json" ), true );
215 | if ( ! in_array( $workflow, $blacklist ) ) {
216 | $blacklist[] = $workflow;
217 | file_put_contents( "$data/config/blacklist.json", utf8_encode( json_encode( $blacklist ) ) );
218 | }
219 | $plist = $endpoints[ $workflow ] . '/info.plist';
220 | $name = exec( "/usr/libexec/PlistBuddy -c \"Print :name\" '$plist' 2> /dev/null" );
221 | exec( "$tn -title 'Packal Updater' -message '$name has been put on the blacklist.'" );
222 | die();
223 | }
224 |
225 | if ( strpos( $q, 'whitelist-' ) !== false ) {
226 | $workflow = str_replace( 'whitelist-', '', $q );
227 | $blacklist = json_decode( file_get_contents( "$data/config/blacklist.json" ), true );
228 | if ( in_array( $workflow, $blacklist ) ) {
229 | unset( $blacklist[ array_search( $workflow, $blacklist ) ] );
230 | file_put_contents( "$data/config/blacklist.json", utf8_encode( json_encode( $blacklist ) ) );
231 | }
232 | $plist = $endpoints[ $workflow ] . '/info.plist';
233 | $name = exec( "/usr/libexec/PlistBuddy -c \"Print :name\" '$plist' 2> /dev/null" );
234 | exec( "$tn -title 'Packal Updater' -message '$name has been removed from the blacklist.'" );
235 | die();
236 | }
237 |
238 | if ( strpos( $q, 'install-cron-script' ) !== false ) {
239 | $dir = escapeshellcmd( exec( 'pwd' ) );
240 | exec( "'$dir/install-alfred-cron-script.sh'" );
241 | exec( "$tn -title 'Packal Updater' -message 'Alfred Cron will now check for workflow updates.'" );
242 | }
243 |
244 |
245 |
--------------------------------------------------------------------------------
/report-usage-data.php:
--------------------------------------------------------------------------------
1 | workflowReporting ) && ( (string) $config->workflowReporting == '1' ) ) ) {
47 | die();
48 | }
49 |
50 | // Make sure that we have an Internet connection before continuing.
51 | if ( checkConnection() == false ) {
52 | die();
53 | }
54 |
55 | // Check if the usage directory exists; make it if it doesn't.
56 | if ( ! file_exists( "$data/usage" ) ) {
57 | mkdir( "$data/usage" );
58 | }
59 |
60 | // This is your unique identifier. If you're reading this, just run the command and see what's up.
61 | $unique = hash( 'sha256',
62 | exec( 'ioreg -rd1 -c IOPlatformExpertDevice | awk \'/IOPlatformUUID/ { split($0, line, "\""); printf("%s\n", line[4]); }\'' ) );
63 |
64 | $unique = utf8_encode( $unique );
65 |
66 | // Create the filename
67 | $date = date( 'Y-W' , time() );
68 | $file = $data . '/usage/' . $date . "-data-$unique.json";
69 |
70 | // This means that we've already generated and sent the file. So, let's just stop now.
71 | if ( file_exists( $file ) ) {
72 | echo 'Already submitted this week.';
73 | die();
74 | }
75 |
76 |
77 | // $me = substr( __DIR__, strrpos( __DIR__, '/' ) + 1 );
78 |
79 | // If the endpoints file does not exist, then we're calling this too early. Just wait a bit.
80 | if ( ! file_exists( "$data/endpoints/endpoints.json" ) ) {
81 | die();
82 | }
83 |
84 | $workflows = json_decode( file_get_contents( "$data/endpoints/endpoints.json" ) );
85 |
86 | foreach ( $workflows as $dir ) :
87 | $w = getWorkflowData( $dir );
88 | if ( is_array( $w ) ) {
89 | $report[] = $w;
90 | }
91 | endforeach;
92 |
93 |
94 | // Total number of workflows installed.
95 | $total = count( $report );
96 |
97 | // We'll send the post array to server. Here's the identifying information for the server
98 | $post = array();
99 | $post['meta'] = array( 'date' => $date , 'total' => $total );
100 |
101 | // Add the Workflows to the post array
102 | $post['workflows'] = $report;
103 | $json = utf8_encode( json_encode( $post ) );
104 |
105 | $data = array( 'info' => $json, 'unique' => $unique, 'task' => 'reporting', 'date' => $date );
106 |
107 | $ch = curl_init();
108 | curl_setopt( $ch, CURLOPT_URL, 'http://api.packal.org' );
109 | curl_setopt( $ch, CURLOPT_USERAGENT, 'packal-workflow-' . hash( 'sha256', $unique ) );
110 | curl_setopt( $ch, CURLOPT_POST, 1 );
111 | curl_setopt( $ch, CURLOPT_POSTFIELDS, $data );
112 | curl_setopt( $ch, CURLOPT_TIMEOUT, 15 );
113 | // curl_setopt( $ch, CURLOPT_HEADER, 1 );
114 | curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 );
115 | curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
116 | curl_setopt( $ch, CURLOPT_ENCODING, 'gzip' );
117 |
118 | $header = curl_getinfo( $ch );
119 | $result = curl_exec( $ch );
120 | curl_close( $ch );
121 |
122 | if ( $result == "It's all good." ) {
123 | // It went through. Yay!
124 | if ( file_put_contents( $file , $json ) !== false ) {
125 | // Recorded the file, so let's move on.
126 | die();
127 | } else {
128 | echo 'We ran into an error when recording the file.';
129 | die();
130 | }
131 | }
132 |
133 | echo 'Error: request not accepted.';
134 | // We're done.
135 | die();
136 |
137 | // Some helpful functions.
138 |
139 | function getWorkflowData( $dir ) {
140 | $plist = "$dir/info.plist";
141 | if ( ! file_exists( $plist ) ) {
142 | return false;
143 | }
144 |
145 | $bundle = utf8_encode( trim( readPlistValue( 'bundleid', $plist ) ) );
146 |
147 | if ( ! $bundle ) {
148 | return false;
149 | }
150 |
151 | // Get the Workflow name
152 | $name = utf8_encode( trim( readPlistValue( 'name', $plist ) ) );
153 |
154 | // Get the author
155 | $author = utf8_encode( trim( readPlistValue( 'createdby', $plist ) ) );
156 |
157 | // Figure out if it's disabled.
158 | $disabled = utf8_encode( readPlistValue( 'disabled', $plist ) );
159 |
160 | // Strangely, sometimes these weren't set on my computer, so, well, that's strange.
161 | // My guess is that they were older workflows, so maybe the problems was older plist
162 | // structures from way-back Alfred 2.
163 | if ( empty( $disabled ) ) { $disabled = 'TRUE';
164 | }
165 | $disabled = strtoupper( $disabled );
166 | if ( file_exists( $dir . '/packal/package.xml' ) ) {
167 | $packal = 'TRUE';
168 | } else { $packal = 'FALSE';
169 | }
170 |
171 | return array( 'name' => $name , 'bundle' => $bundle , 'author' => $author, 'disabled' => $disabled, 'packal' => $packal );
172 |
173 | }
174 |
175 | function checkConnection() {
176 | ini_set( 'default_socket_timeout', 1 );
177 |
178 | // First test
179 | exec( 'ping -c 1 -t 1 www.github.com', $pingResponse, $pingError );
180 | if ( $pingError == 14 ) {
181 | return false;
182 | }
183 |
184 | // Second Test
185 | $connection = @fsockopen( 'www.github.com', 80, $errno, $errstr, 1 );
186 |
187 | if ( $connection ) {
188 | $status = true;
189 | fclose( $connection );
190 | } else {
191 | $status = false;
192 | }
193 | return $status;
194 | }
195 |
196 | function readPlistValue( $key, $plist ) {
197 | return exec( "/usr/libexec/PlistBuddy -c \"Print :$key\" '$plist' 2> /dev/null" );
198 | }
199 |
--------------------------------------------------------------------------------
/screenshots/gui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/screenshots/gui.png
--------------------------------------------------------------------------------
/screenshots/packal-blacklist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/screenshots/packal-blacklist.png
--------------------------------------------------------------------------------
/screenshots/packal-setup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/screenshots/packal-setup.png
--------------------------------------------------------------------------------
/screenshots/packal-start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/screenshots/packal-start.png
--------------------------------------------------------------------------------
/screenshots/packal-update-no-internet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/screenshots/packal-update-no-internet.png
--------------------------------------------------------------------------------
/screenshots/packal-update.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/screenshots/packal-update.png
--------------------------------------------------------------------------------
/screenshots/packal-updater-alfred.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/screenshots/packal-updater-alfred.gif
--------------------------------------------------------------------------------
/screenshots/packal-updater-gui.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/screenshots/packal-updater-gui.gif
--------------------------------------------------------------------------------
/screenshots/reporting-unique-id.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/screenshots/reporting-unique-id.png
--------------------------------------------------------------------------------
/script-set-option.php:
--------------------------------------------------------------------------------
1 | $option ) && ( ! empty( $config->$option ) ) ) {
21 | if ( $option == 'backups' ) {
22 | $value = (int) $config->$option;
23 | } else {
24 | $value = $config->$option;
25 | }
26 | }
27 | }
28 | $options = array(
29 | 'authorName' => 'Please enter the name you use when you write workflows',
30 | 'packalAccount' => 'Do you have an account on Packal? Please answer yes or no.',
31 | 'username' => 'Please enter your Packal username',
32 | 'workflowReporting' => 'Would you like to send anonymous data about your installed workflows to Packal.org? Please enter yes or no.',
33 | 'backups' => 'Please enter the number of backups you would like to keep',
34 | );
35 |
36 | $bool = array( 'packalAccount', 'workflowReporting' );
37 |
38 | if ( in_array( $option, $bool ) ) {
39 | if ( $option == 'workflowReporting' ) {
40 | if ( $config->workflowReporting == 1 ) {
41 | $w->result( 'option-set-workflowReporting-1', 'option-set-workflowReporting-1', 'Send anonymous data to Packal.org.', 'Currently selected', 'assets/icons/svn-commit.png', 'yes', '' );
42 | $w->result( 'option-set-workflowReporting-0', 'option-set-workflowReporting-0', 'Do not send anonymous data to Packal.org.', '', '', 'yes', '' );
43 | } else {
44 | $w->result( 'option-set-workflowReporting-1', 'option-set-workflowReporting-1', 'Send anonymous data to Packal.org.', '', 'assets/icons/svn-commit.png', 'yes', '' );
45 | $w->result( 'option-set-workflowReporting-0', 'option-set-workflowReporting-0', 'Do not send anonymous data to Packal.org.', 'Currently selected', '', 'yes', '' );
46 | }
47 | } elseif ( $option == 'packalAccount' ) {
48 | $w->result( 'option-set-packalAccount-1', 'option-set-packalAccount-1', 'I do have an account on Packal.org', '', '', 'yes', '' );
49 | $w->result( 'option-set-packalAccount-0', 'option-set-packalAccount-0', 'I do not have an account on Packal.org', '', '', 'yes', '' );
50 | }
51 | } else {
52 | if ( empty( $value ) ) {
53 | $w->result( "option-set-$option-$value", "option-set-$option-$value", $options[ $option ], "$value", '', 'no', '' );
54 | } elseif ( $option == 'backups' ) {
55 | if ( ( $value > 9 ) || ( $value < 0 ) ) {
56 | $w->result( "option-set-$option-$value", "option-set-$option-$value", 'Error: The number of backups must be positive and less than 10', '', '', 'no', '' );
57 | } elseif ( ! is_numeric( $value ) ) {
58 | $w->result( "option-set-$option-$value", "option-set-$option-$value", 'Error: The number of backups must be an integer', '', '', 'no', '' );
59 | } else {
60 | $value = (int) $value;
61 | $w->result( "option-set-$option-$value", "option-set-$option-$value", "Set the number of backups to keep to '$value'", "$value", '', 'yes', '' );
62 | }
63 | } else {
64 | if ( $option == 'username' ) {
65 | if ( $config->packalAccount == 1 ) {
66 | $w->result( '', "option-set-$option-$value", 'Set your ' . $option . " to '$value'", "$value", '', 'yes', '' );
67 | $w->result( '', "option-set-$option-", 'Clear Packal Username', '', '', 'yes', '' );
68 | }
69 | } elseif ( $option == 'authorName' ) {
70 | if ( empty( $config->authorName ) ) {
71 | $w->result( '', "option-set-$option-$value", "Set your author name to '$value'", "$value", '', 'yes', '' );
72 | } else {
73 | $w->result( '', "option-set-$option-$value", "Set your author name to '$value'", "$value", '', 'yes', '' );
74 | $w->result( '', "option-set-$option-", 'Clear Author Name', '', '', 'yes', '' );
75 | }
76 | } else {
77 | $w->result( "option-set-$option-$value", "option-set-$option-$value", 'Set your ' . $option . " to '$value'", $value, '', 'yes', '' );
78 | }
79 | }
80 | }
81 | }
82 |
83 | setOption();
84 |
85 | echo $w->toxml();
86 |
87 |
88 |
--------------------------------------------------------------------------------
/script.php:
--------------------------------------------------------------------------------
1 | result( '', '', 'Warning: no viable Internet connection',
40 | 'Some features of this workflow will be unavailable without a solid Internet connection', 'assets/icons/task-attention.png', 'no', '');
41 | }
42 |
43 | if ( ! file_exists( $data ) ) {
44 | mkdir( "$data", 0775, true );
45 | }
46 | if ( ! file_exists( $cache ) ) {
47 | mkdir( "$cache", 0775, true );
48 | }
49 | if ( ! file_exists( "$data/config" ) ) {
50 | mkdir( "$data/config", 0775, true );
51 | }
52 | if ( ! file_exists( "$data/endpoints" ) ) {
53 | mkdir( "$data/endpoints", 0775, true );
54 | }
55 |
56 | if ( ! file_exists( "$data/config/blacklist.json" ) ) {
57 | // Make an empty blacklist file if one doesn't exist.
58 | $blacklist = array();
59 | file_put_contents( "$data/config/blacklist.json", utf8_encode( json_encode( $blacklist ) ) );
60 | }
61 |
62 | generateEndpoints();
63 |
64 | // Not all of these are used right now.
65 | if ( ! file_exists( "$data/config/config.xml" ) ) {
66 | $d = '';
67 | $config = new SimpleXMLElement( $d );
68 | $config->packalAccount = 0;
69 | $config->forcePackal = 0;
70 | $config->backups = 3;
71 | $config->username = '';
72 | $config->authorName = '';
73 | $config->workflowReporting = '1';
74 | $config->notifications = '2';
75 | $config->apiKey = '';
76 | $config->asXML( "$data/config/config.xml" );
77 | unset( $config );
78 | } else {
79 | $config = simplexml_load_file( "$data/config/config.xml" );
80 | }
81 |
82 | if ( ! file_exists( "$data/manifest.xml" ) ) {
83 | // This should be taken care of in the firstRun() call,
84 | // but the redundancy is fine.
85 | if ( getManifest() == false ) {
86 | $w->result( '', '', 'Error: Packal Updater',
87 | 'The workflow manifest is not valid, and there is no valid Internet connection to retrieve a new one.', 'assets/icons/task-reject.png', 'no', '');
88 | echo $w->toxml();
89 | die();
90 | }
91 | }
92 |
93 | // Update the manifest if past cache.
94 | // This is a potential failure spot.
95 | if ( $connection !== false ) {
96 | exec( "'" . __DIR__ . "/cli/packal.sh' update" );
97 | }
98 |
99 | // Do the workflow reporting script as long as the config option is set.
100 | // if ( $config->workflowReporting == '1' ) {
101 | // exec( "nohup php '" . __DIR__ . "/report-usage-data.php' > /dev/null 2>&1 &" );
102 | // }
103 |
104 | $blacklist = json_decode( file_get_contents( "$data/config/blacklist.json" ), true );
105 | $manifest = @simplexml_load_file( "$data/manifest.xml" );
106 |
107 | // The manifest is not valid. Let's try to get it before we fail.
108 | if ( empty( $manifest ) ) {
109 | if ( getManifest() === false ) {
110 | $w->result( '', '', 'Error: Packal Updater',
111 | 'The workflow manifest is not valid, and there is no valid Internet connection to retrieve a new one.', 'assets/icons/task-reject.png', 'no', '');
112 | echo $w->toxml();
113 | die();
114 | }
115 | // So, the we didn't get an error, but let's try to make sure it is valid XML.
116 | $manifest = @simplexml_load_file( "$data/manifest.xml" );
117 | if ( empty( $manifest ) ) {
118 | $w->result( '', '', 'Error: Packal Updater',
119 | 'The workflow manifest is not valid, and there is no valid Internet connection to retrieve a new one.', 'assets/icons/task-reject.png', 'no', '');
120 | echo $w->toxml();
121 | die();
122 | }
123 | }
124 |
125 | // Okay, we're good. Or, at least we should be.
126 |
127 | $json = json_decode( file_get_contents( "$data/endpoints/endpoints.json" ), true );
128 | $mine = array_keys( $json );
129 | $count = count( $manifest->workflow );
130 | $me = exec( "php '" . __DIR__ . "/cli/packal.php' getOption username" );
131 |
132 | foreach ( $manifest->workflow as $wf ) :
133 |
134 | if ( in_array( $wf->bundle, $mine ) ) {
135 | $packal[] = (string) $wf->bundle;
136 |
137 | if ( isset( $me ) && ( ! empty( $me ) ) && ( $wf->author == $me ) ) {
138 | $mywf[] = (string) $wf->bundle;
139 | }
140 | }
141 | endforeach;
142 | unset( $wf );
143 |
144 | // Grab manifest information.
145 | foreach ( $manifest as $m ) :
146 | $manifestBundles[] = $m->bundle;
147 | $wf[ "$m->bundle" ]['name'] = $m->name;
148 | $wf[ "$m->bundle" ]['author'] = $m->author;
149 | $wf[ "$m->bundle" ]['version'] = $m->version;
150 | $wf[ "$m->bundle" ]['short'] = $m->short;
151 | $wf[ "$m->bundle" ]['updated'] = $m->updated;
152 | $wf[ "$m->bundle" ]['url'] = $m->url;
153 | endforeach;
154 |
155 | foreach ( $json as $k => $v ) :
156 | $pattern = '/[\/A-Za-z0-9-_ .]{1,}\/user\.workflow\.([0-9A-Z.-]{1,})/';
157 | preg_match( $pattern, $v, $matches );
158 | if ( isset( $matches[1] ) ) {
159 | $json[ $k ] = 'user.workflow.' . $matches[1];
160 | }
161 | endforeach;
162 | foreach ( $json as $k => $v ) :
163 | if ( file_exists( "../$v/packal/package.xml" ) ) {
164 | $p = simplexml_load_file( "../$v/packal/package.xml" );
165 | if ( in_array( $k, $manifestBundles ) ) {
166 | if ( (string) $p->version != $wf[ "$k" ]['version'] ) {
167 | if ( ! in_array( $k, $blacklist ) ) {
168 | $updates[ $k ]['name'] = (string) $p->name;
169 | $updates[ $k ]['path'] = "../$v";
170 | $updates[ $k ]['version'] = (string) $p->version;
171 | }
172 | }
173 | }
174 | }
175 | endforeach;
176 |
177 | if ( empty( $q[1] ) ) {
178 | if ( ! isset( $updates ) ) {
179 | $w->result( 'updates', 'updates', 'All of your workflows are up to date.', '', 'assets/icons/task-complete.png', 'no', '' );
180 | } else {
181 | if ( count( $updates ) > 1 ) {
182 | $message = 'There are ' . count( $updates ) . ' updates pending.';
183 | } else { $message = 'There is 1 update pending.';
184 | }
185 |
186 | $w->result( 'updates', 'updates', 'Updates available', $message, '', 'no', 'update' );
187 | }
188 |
189 | if ( ( time() - filemtime( "$data/manifest.xml" ) < 86400 ) ) {
190 | $manifestTime = getManifestModTime();
191 | $w->result( '', 'manifest-update', 'The manifest is up to date.', "Last updated $manifestTime", 'assets/icons/task-complete.png', 'yes', '' );
192 | } else {
193 | $manifestTime = getManifestModTime();
194 | $w->result( '', 'manifest-update', 'The manifest is out of date.', "Last updated $manifestTime", 'assets/icons/task-attention.png', 'yes', '' );
195 | }
196 |
197 | if ( $gui === true ) {
198 | $w->result( 'open-gui', 'open-gui', "Open Graphical 'Application'",
199 | 'Configure this workflow, Update workflows, and learn about this workflow. (RECOMMENDED)', 'assets/icons/applications-education-miscellaneous.png', 'yes', '');
200 | } else {
201 | $w->result( '', '', "GUI Not Available'",
202 | 'A GUI to configure and operate this workflow is available if you have OS X 10.9 or 10.10.', 'assets/icons/applications-education-miscellaneous.png', 'no', '');
203 | }
204 |
205 | if ( isset( $mywf ) ) {
206 | $mywf = count( $mywf );
207 | } else { $mywf = 0;
208 | }
209 |
210 | // if ( isset( $config->authorName ) && ( ! empty( $config->authorName ) ) {
211 | // $w->result( '', '', 'Informational',
212 | // "There are $count workflows in the manifest," .
213 | // " of which, you have " . count( $packal ) .
214 | // " installed, and you wrote " . $mywf . " of those.", '', 'no', '');
215 | // }
216 |
217 | $w->result( 'blacklist', 'blacklist', 'Manage Blacklist', 'Configure which workflows Packal updates', 'assets/icons/flag-black.png', 'no', 'blacklist' );
218 |
219 | $w->result( '', '', 'Informational',
220 | "There are $count workflows in the manifest," .
221 | ' of which, you have ' . count( $packal ) .
222 | ' installed, and you wrote ' . $mywf . ' of those.', 'assets/icons/help-about.png', 'no', '');
223 |
224 | $w->result( '', 'setup', 'Configure', 'Make this workflow work best for you.', 'assets/icons/applications-system.png', 'no', 'setup' );
225 |
226 | echo $w->toxml();
227 | die();
228 | }
229 |
230 | if ( strpos( $q[1], 'update' ) !== false ) {
231 | if ( ! isset( $updates ) ) {
232 | $updates = array();
233 | }
234 | if ( count( $updates ) > 0 ) {
235 | if ( count( $updates ) > 1 ) {
236 | // Don't allow the updates if there is no internet connection.
237 | if ( $connection !== false ) {
238 | $w->result( 'update-all', 'update-all', 'Update all workflows', '', '', 'yes', '' );
239 | }
240 | }
241 | foreach ( $updates as $k => $v ) :
242 |
243 | // Get the workflow icon, if it exists, otherwise, fallback to package icon
244 | if ( file_exists( $v['path'] . '/icon.png' ) ) {
245 | $icon = $v['path'] . '/icon.png';
246 | } else { $icon = 'assets/icons/package.png';
247 | }
248 | if ( $connection !== false ) {
249 | $w->result( "update-$k", "update-$k", 'Update ' . $v['name'], 'Update version ' . $v['version'] . ' => ' . $wf[ $k ]['version'], $v['path'] . '/icon.png', '', '' );
250 | } else { $w->result( "update-$k", '', 'An update for ' . $v['name'] . ' is available.', 'Update version ' . $v['version'] . ' => ' . $wf[ $k ]['version'] . '. << Exception: no viable Internet connection. Update impossible. >>' , $v['path'] . '/icon.png', 'no', '' );
251 | }
252 | endforeach;
253 | } else {
254 | $w->result( '', '', 'All of your workflows are up to date.', '', 'assets/icons/task-complete.png', 'no', '' );
255 | }
256 |
257 | echo $w->toxml();
258 | // We're done here.
259 | die();
260 | }
261 |
262 | if ( strpos( $q[1], 'setup' ) !== false ) {
263 |
264 | // The next argument removes the forced-setup option.
265 | if ( ( ! file_exists( "$data/config/first-run-alfred" ) ) && ( ! file_exists( "$data/config/first-run" ) ) ) {
266 | file_put_contents( "$data/config/first-run-alfred", 'done' );
267 | }
268 |
269 | $options = array(
270 | 'authorName' => 'What name do you use when you write workflows?',
271 | 'packalAccount' => 'Do you have an account on Packal?',
272 | 'username' => 'What is your Packal username?',
273 | 'workflowReporting' => 'Would you like to send anonymous data about your installed workflows to Packal.org?',
274 | 'backups' => 'How many backups of workflows would you like to keep?',
275 | );
276 | foreach ( $options as $k => $v ) :
277 | if ( isset( $config->$k ) ) {
278 | if ( ( (string) $config->$k == '1' ) && ( $k != 'backups' ) ) {
279 | $message = 'Current value: Yes';
280 | } elseif ( ( (string) $config->$k == '0' ) && ( $k != 'backups' ) ) {
281 | $message = 'Current value: No';
282 | } else {
283 | if ( ! empty( $config->$k ) ) {
284 | $message = 'Current value: ' . $config->$k;
285 | } else { $message = '< not set >';
286 | }
287 | }
288 | } else {
289 | $message = 'Not set.';
290 | }
291 |
292 | // Setup icons per option
293 | $icon = 'assets/icons/';
294 | switch ( $k ) :
295 | case 'authorName':
296 | $icon .= 'code-context.png';
297 | break;
298 | case 'username' :
299 | $icon .= 'im-user.png';
300 | break;
301 | case 'workflowReporting' :
302 | $icon .= 'svn-commit.png';
303 | break;
304 | case 'backups' :
305 | $icon .= 'player-time.png';
306 | break;
307 | case 'packalAccount' :
308 | $icon .= 'flag.png';
309 | break;
310 | default:
311 | $icon = '';
312 | break;
313 | endswitch;
314 |
315 | if ( ( $k == 'username' ) && ( $config->packalAccount == 1 ) ) {
316 | $w->result( "set-$k", "set-$k", $v, $message, $icon, 'yes', '' );
317 | } elseif ( ( $k == 'packalAccount' ) && ( $config->packalAccount == 1 ) ) {
318 | continue;
319 | } elseif ( ! ( $k == 'username' ) ) {
320 | $w->result( "set-$k", "set-$k", $v, $message, $icon, 'yes', '' );
321 | }
322 | endforeach;
323 |
324 | echo $w->toxml();
325 | die();
326 |
327 | } elseif ( strpos( $q[1], 'blacklist' ) !== false ) {
328 | // Option to Blacklist a workflow
329 |
330 | // @TODO: Sort the workflows by name.
331 | foreach ( $json as $k => $v ) :
332 | if ( file_exists( "../$v/packal/package.xml" ) ) {
333 | if ( in_array( $k, $manifestBundles ) ) {
334 | if ( ! in_array( $k, $blacklist ) ) {
335 | $w->result( "blacklist-$k", "blacklist-$k", "Add '" . $wf[ $k ]['name'] . "' to blacklist", "Prevent Packal from updating '" . $wf[ $k ]['name'] . "' ($k)", 'assets/icons/user-online.png', 'yes', '' );
336 | } else {
337 | $w->result( "whitelist-$k", "whitelist-$k", "Remove '" . $wf[ $k ]['name'] . "' from blacklist", "Let Packal update '" . $wf[ $k ]['name'] . "' ($k)", 'assets/icons/user-offline.png', 'yes', '' );
338 | }
339 | }
340 | }
341 | endforeach;
342 |
343 | echo $w->toxml();
344 | die();
345 | }
346 |
347 | // For all good measures....
348 | echo $w->toxml();
349 | die();
350 |
--------------------------------------------------------------------------------
/workflow/Packal Updater.alfredworkflow:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shawnrice/packal-updater/3e7481e04aeece6cf2792a93906735cfecac04d3/workflow/Packal Updater.alfredworkflow
--------------------------------------------------------------------------------